int elektraCryptoGcryDecrypt(elektraCryptoHandle *handle, Key *k, Key *errorKey) { kdb_octet_t *value = (kdb_octet_t*)keyValue(k); const size_t valueLen = keyGetValueSize(k); kdb_octet_t *output; kdb_octet_t cipherBuffer[ELEKTRA_CRYPTO_GCRY_BLOCKSIZE]; kdb_octet_t contentBuffer[ELEKTRA_CRYPTO_GCRY_BLOCKSIZE]; kdb_unsigned_long_t written = 0; gcry_error_t gcry_err; // initialize crypto header data kdb_unsigned_long_t contentLen = 0; kdb_octet_t flags = ELEKTRA_CRYPTO_FLAG_NONE; // check if key has been encrypted in the first place const Key *metaEncrypted = keyGetMeta(k, ELEKTRA_CRYPTO_META_ENCRYPT); if (metaEncrypted == NULL || strlen(keyValue(metaEncrypted)) == 0) { // nothing to do return 1; } // plausibility check if (valueLen % ELEKTRA_CRYPTO_GCRY_BLOCKSIZE != 0) { ELEKTRA_SET_ERROR(128, errorKey, "value length is not a multiple of the block size"); return (-1); } // prepare buffer for plain text output output = elektraMalloc(valueLen); if (output == NULL) { ELEKTRA_SET_ERROR(87, errorKey, "Memory allocation failed"); return (-1); } // decrypt the header (1st block) memcpy(cipherBuffer, value, ELEKTRA_CRYPTO_GCRY_BLOCKSIZE); gcry_err = gcry_cipher_decrypt(*handle, contentBuffer, ELEKTRA_CRYPTO_GCRY_BLOCKSIZE, cipherBuffer, ELEKTRA_CRYPTO_GCRY_BLOCKSIZE); if (gcry_err != 0) { ELEKTRA_SET_ERRORF(128, errorKey, "Decryption failed because: %s", gcry_strerror(gcry_err)); elektraFree(output); return (-1); } // restore the header data memcpy(&flags, contentBuffer, sizeof(flags)); memcpy(&contentLen, contentBuffer+sizeof(flags), sizeof(contentLen)); // decrypt content block by block // (i = start of the current block and the 1st block has already been consumed) for (kdb_unsigned_long_t i = ELEKTRA_CRYPTO_GCRY_BLOCKSIZE; i < valueLen; i += ELEKTRA_CRYPTO_GCRY_BLOCKSIZE) { memcpy(cipherBuffer, (value + i), ELEKTRA_CRYPTO_GCRY_BLOCKSIZE); gcry_err = gcry_cipher_decrypt(*handle, contentBuffer, ELEKTRA_CRYPTO_GCRY_BLOCKSIZE, cipherBuffer, ELEKTRA_CRYPTO_GCRY_BLOCKSIZE); if (gcry_err != 0) { ELEKTRA_SET_ERRORF(128, errorKey, "Decryption failed because: %s", gcry_strerror(gcry_err)); elektraFree(output); return (-1); } memcpy((output + i - ELEKTRA_CRYPTO_GCRY_BLOCKSIZE), contentBuffer, ELEKTRA_CRYPTO_GCRY_BLOCKSIZE); written += ELEKTRA_CRYPTO_GCRY_BLOCKSIZE; } if (written < contentLen) { ELEKTRA_SET_ERROR(128, errorKey, "Content was shorter than described in the header"); elektraFree(output); return (-1); } // write back the cipher text to the key if ((flags & ELEKTRA_CRYPTO_FLAG_STRING) == ELEKTRA_CRYPTO_FLAG_STRING) { keySetString(k, (const char*)output); } else if ((flags & ELEKTRA_CRYPTO_FLAG_NULL) == ELEKTRA_CRYPTO_FLAG_NULL || contentLen == 0) { keySetBinary(k, NULL, 0); } else { keySetBinary(k, output, contentLen); } elektraFree(output); return 1; }
static int evalCondition(const char *leftSide, Comparator cmpOp, const char *rightSide, KeySet *ks, Key *parentKey) { char *lookupName = NULL; char *compareTo = NULL; Key *key; int len; long result = 0; if(rightSide[0] == '\'') { char *endPos = strchr(rightSide+1, '\''); if(!endPos) { result = -1; goto Cleanup; } if(elektraRealloc((void **)&compareTo, endPos-rightSide) < 0) { ELEKTRA_SET_ERROR(87, parentKey, "Out of memory"); result = -1; goto Cleanup; } memset(compareTo, 0, endPos-rightSide); strncat(compareTo, rightSide+1, endPos-rightSide-1); } else if(rightSide && elektraStrLen(rightSide) > 1) { len = keyGetNameSize(parentKey)+elektraStrLen(rightSide); if(elektraRealloc((void **)&lookupName, len) < 0) { ELEKTRA_SET_ERROR(87, parentKey, "Out of memory"); result = -1; goto Cleanup; } snprintf(lookupName, len, "%s/%s", keyName(parentKey), rightSide); key = ksLookupByName(ks, lookupName, 0); if(!key) { ELEKTRA_SET_ERRORF(133, parentKey, "Key %s doesn't exist", lookupName); result = -1; goto Cleanup; } if(elektraRealloc((void **)&compareTo, keyGetValueSize(key)) < 0) { ELEKTRA_SET_ERROR(87, parentKey, "Out of memory"); result = -1; goto Cleanup; } strcpy(compareTo, keyString(key)); } len = keyGetNameSize(parentKey)+elektraStrLen(leftSide); if(elektraRealloc((void **)&lookupName, len) < 0) { ELEKTRA_SET_ERROR(87, parentKey, "Out of memory"); result = -1; goto Cleanup; } snprintf(lookupName, len, "%s/%s", keyName(parentKey), leftSide); key = ksLookupByName(ks, lookupName, 0); if(!key) { ELEKTRA_SET_ERRORF(133, parentKey, "Key %s doesn't exist", lookupName); result = -1; goto Cleanup; } long ret; ret = compareStrings(keyString(key), compareTo); switch(cmpOp) { case EQU: if(!ret) result = 1; break; case NOT: if(ret) result = 1; break; case LT: if(ret < 0) result = 1; break; case LE: if(ret <= 0) result = 1; break; case GT: if(ret > 0) result = 1; break; case GE: if(ret >= 0) result = 1; break; case SET: keySetString(key, compareTo); result = 1; break; default: result = -1; break; } //freeing allocated heap Cleanup: if(lookupName) elektraFree(lookupName); if(compareTo) elektraFree(compareTo); return result; }
static int iniKeyToElektraKey (void *vhandle, const char *section, const char *name, const char *value, unsigned short lineContinuation) { CallbackHandle *handle = (CallbackHandle *)vhandle; Key *appendKey = keyDup (handle->parentKey); keySetMeta(appendKey, "ini/lastSection", 0); if (!section || *section == '\0') { section = INTERNAL_ROOT_SECTION; } appendKey = createUnescapedKey(appendKey, section); short mergeSections = 0; Key *existingKey = NULL; if ((existingKey = ksLookup(handle->result, appendKey, KDB_O_NONE))) { if (keyGetMeta(existingKey, "ini/duplicate")) { mergeSections = 1; } } setSectionNumber(handle->parentKey, appendKey, handle->result); appendKey = createUnescapedKey(appendKey, name); existingKey = ksLookup(handle->result, appendKey, KDB_O_NONE); if (existingKey) { //a key with the same name already exists if (handle->array) { //array support is turned on keySetMeta(appendKey, "ini/section", 0); if (keyGetMeta(existingKey, "ini/array")) { //array already exists, appending new key const char *lastIndex = keyString(keyGetMeta(existingKey, "ini/array")); keyAddBaseName(appendKey, lastIndex); keySetMeta(appendKey, "order/parent", 0); keySetMeta(appendKey, "ini/array", 0); keySetMeta(appendKey, "order", 0); if (elektraArrayIncName(appendKey) == 1) { return -1; } keySetString(appendKey, value); keySetMeta(appendKey, "ini/key", 0); ksAppendKey(handle->result, appendKey); keySetMeta(existingKey, "ini/array", keyBaseName(appendKey)); ksAppendKey(handle->result, existingKey); } else { //creating a new array Key *sectionKey = keyDup(appendKey); keyAddName(sectionKey, ".."); char *origVal = strdup(keyString(existingKey)); keySetString(appendKey, ""); keySetMeta(appendKey, "ini/array", "#1"); keySetMeta(appendKey, "order/parent", keyName(sectionKey)); setSectionNumber(handle->parentKey, appendKey, handle->result); setOrderNumber(handle->parentKey, appendKey); keySetMeta(appendKey, "ini/key", ""); ksAppendKey(handle->result, keyDup(appendKey)); keySetMeta(appendKey, "ini/key", 0); keySetMeta(appendKey, "ini/array", 0); keySetMeta(appendKey, "parent", 0); keyAddName(appendKey, "#"); keySetMeta(appendKey, "order", 0); if (elektraArrayIncName(appendKey) == -1) { free(origVal); return -1; } keySetString(appendKey, origVal); ksAppendKey(handle->result, keyDup(appendKey)); free(origVal); if (elektraArrayIncName(appendKey) == -1) { return -1; } keySetMeta(appendKey, "parent", 0); keySetString(appendKey, value); ksAppendKey(handle->result, keyDup(appendKey)); keyDel(appendKey); keyDel(sectionKey); } return 1; } else if(!lineContinuation) { ELEKTRA_SET_ERRORF(141, handle->parentKey, "Key: %s\n", name); return -1; } } setSectionNumber(handle->parentKey, appendKey, handle->result); if (value == NULL) keySetMeta(appendKey, "ini/empty", ""); if (!lineContinuation) { flushCollectedComment (handle, appendKey); keySetString (appendKey, value); keySetMeta(appendKey, "ini/key", ""); ksAppendKey (handle->result, appendKey); if (mergeSections) { keySetMeta(appendKey, "order", 0); insertNewKeyIntoExistendOrder(appendKey, handle->result); } else { setOrderNumber(handle->parentKey, appendKey); } } else { existingKey = ksLookup (handle->result, appendKey, KDB_O_NONE); keyDel (appendKey); /* something went wrong before because this key should exist */ if (!existingKey) return -1; elektraKeyAppendLine(existingKey, value); } return 1; }
int elektraCryptoGcryEncrypt(elektraCryptoHandle *handle, Key *k, Key *errorKey) { const kdb_octet_t *value = (kdb_octet_t*)keyValue(k); size_t outputLen; gcry_error_t gcry_err; kdb_octet_t *output; kdb_octet_t cipherBuffer[ELEKTRA_CRYPTO_GCRY_BLOCKSIZE]; kdb_octet_t contentBuffer[ELEKTRA_CRYPTO_GCRY_BLOCKSIZE] = { 0 }; // check if key has been marked for encryption const Key *metaEncrypt = keyGetMeta(k, ELEKTRA_CRYPTO_META_ENCRYPT); if (metaEncrypt == NULL || strlen(keyValue(metaEncrypt)) == 0) { // nothing to do return 1; } // prepare the crypto header data const kdb_unsigned_long_t contentLen = keyGetValueSize(k); kdb_octet_t flags; switch (keyIsString(k)) { case 1: // string flags = ELEKTRA_CRYPTO_FLAG_STRING; break; case -1: // NULL pointer flags = ELEKTRA_CRYPTO_FLAG_NULL; break; default: // binary flags = ELEKTRA_CRYPTO_FLAG_NONE; break; } // prepare buffer for cipher text output // NOTE the header goes into the first block if (contentLen % ELEKTRA_CRYPTO_GCRY_BLOCKSIZE == 0) { outputLen = (contentLen / ELEKTRA_CRYPTO_GCRY_BLOCKSIZE) + 1; } else { outputLen = (contentLen / ELEKTRA_CRYPTO_GCRY_BLOCKSIZE) + 2; } outputLen *= ELEKTRA_CRYPTO_GCRY_BLOCKSIZE; output = elektraMalloc(outputLen); if (output == NULL) { ELEKTRA_SET_ERROR(87, errorKey, "Memory allocation failed"); return (-1); } // encrypt the header (1st block) memcpy(contentBuffer, &flags, sizeof(flags)); memcpy(contentBuffer+sizeof(flags), &contentLen, sizeof(contentLen)); gcry_err = gcry_cipher_encrypt(*handle, cipherBuffer, ELEKTRA_CRYPTO_GCRY_BLOCKSIZE, contentBuffer, ELEKTRA_CRYPTO_GCRY_BLOCKSIZE); if (gcry_err != 0) { ELEKTRA_SET_ERRORF(127, errorKey, "Encryption failed because: %s", gcry_strerror(gcry_err)); elektraFree(output); return (-1); } memcpy(output, cipherBuffer, ELEKTRA_CRYPTO_GCRY_BLOCKSIZE); // encrypt content block by block (i = start of the current block) for (kdb_unsigned_long_t i = 0; i < contentLen; i += ELEKTRA_CRYPTO_GCRY_BLOCKSIZE) { // load content partition into the content buffer kdb_unsigned_long_t partitionLen = ELEKTRA_CRYPTO_GCRY_BLOCKSIZE; if ((i + 1) * ELEKTRA_CRYPTO_GCRY_BLOCKSIZE > contentLen) { partitionLen = contentLen - (i * ELEKTRA_CRYPTO_GCRY_BLOCKSIZE); } memcpy(contentBuffer, (value + i), partitionLen); gcry_err = gcry_cipher_encrypt(*handle, cipherBuffer, ELEKTRA_CRYPTO_GCRY_BLOCKSIZE, contentBuffer, ELEKTRA_CRYPTO_GCRY_BLOCKSIZE); if (gcry_err != 0) { ELEKTRA_SET_ERRORF(127, errorKey, "Encryption failed because: %s", gcry_strerror(gcry_err)); elektraFree(output); return (-1); } memcpy((output + i + ELEKTRA_CRYPTO_GCRY_BLOCKSIZE), cipherBuffer, ELEKTRA_CRYPTO_GCRY_BLOCKSIZE); } // write back the cipher text to the key keySetBinary(k, output, outputLen); elektraFree(output); return 1; }
/** * @brief Retrieve keys in an atomic and universal way. * * @pre The @p handle must be passed as returned from kdbOpen(). * * @pre The @p returned KeySet must be a valid KeySet, e.g. constructed * with ksNew(). * * @pre The @p parentKey Key must be a valid Key, e.g. constructed with * keyNew(). * * If you pass NULL on any parameter kdbGet() will fail immediately without doing anything. * * The @p returned KeySet may already contain some keys, e.g. from previous * kdbGet() calls. The new retrieved keys will be appended using * ksAppendKey(). * * If not done earlier kdbGet() will fully retrieve all keys under the @p parentKey * folder recursively (See Optimization below when it will not be done). * * @note kdbGet() might retrieve more keys than requested (that are not * below parentKey). These keys must be passed to calls of kdbSet(), * otherwise they will be lost. This stems from the fact that the * user has the only copy of the whole configuration and backends * only write configuration that was passed to them. * For example, if you kdbGet() "system/mountpoint/interest" * you will not only get all keys below system/mountpoint/interest, * but also all keys below system/mountpoint (if system/mountpoint * is a mountpoint as the name suggests, but * system/mountpoint/interest is not a mountpoint). * Make sure to not touch or remove keys outside the keys of interest, * because others may need them! * * @par Example: * This example demonstrates the typical usecase within an application * (without error handling). * * @include kdbget.c * * When a backend fails kdbGet() will return -1 with all * error and warning information in the @p parentKey. * The parameter @p returned will not be changed. * * @par Optimization: * In the first run of kdbGet all requested (or more) keys are retrieved. On subsequent * calls only the keys are retrieved where something was changed * inside the key database. The other keys stay in the * KeySet returned as passed. * * It is your responsibility to save the original keyset if you * need it afterwards. * * If you want to be sure to get a fresh keyset again, you need to open a * second handle to the key database using kdbOpen(). * * @param handle contains internal information of @link kdbOpen() opened @endlink key database * @param parentKey is used to add warnings and set an error * information. Additionally, its name is a hint which keys * should be retrieved (it is possible that more are retrieved, see Note above). * - cascading keys (starting with /) will retrieve the same path in all namespaces * - / will retrieve all keys * @param ks the (pre-initialized) KeySet returned with all keys found * will not be changed on error or if no update is required * @see ksLookup(), ksLookupByName() for powerful * lookups after the KeySet was retrieved * @see kdbOpen() which needs to be called before * @see kdbSet() to save the configuration afterwards and kdbClose() to * finish affairs with the key database. * @retval 1 if the keys were retrieved successfully * @retval 0 if there was no update - no changes are made to the keyset then * @retval -1 on failure - no changes are made to the keyset then * @ingroup kdb */ int kdbGet (KDB * handle, KeySet * ks, Key * parentKey) { elektraNamespace ns = keyGetNamespace (parentKey); if (ns == KEY_NS_NONE) { return -1; } Key * oldError = keyNew (keyName (parentKey), KEY_END); copyError (oldError, parentKey); if (ns == KEY_NS_META) { clearError (parentKey); keyDel (oldError); ELEKTRA_SET_ERRORF (104, parentKey, "metakey with name \"%s\" passed to kdbGet", keyName (parentKey)); return -1; } if (ns == KEY_NS_EMPTY) { ELEKTRA_ADD_WARNING (105, parentKey, "invalid key name passed to kdbGet"); } int errnosave = errno; Key * initialParent = keyDup (parentKey); ELEKTRA_LOG ("now in new kdbGet (%s)", keyName (parentKey)); Split * split = splitNew (); if (!handle || !ks) { clearError (parentKey); ELEKTRA_SET_ERROR (37, parentKey, "handle or ks null pointer"); goto error; } elektraGlobalGet (handle, ks, parentKey, PREGETSTORAGE, INIT); elektraGlobalGet (handle, ks, parentKey, PREGETSTORAGE, MAXONCE); elektraGlobalGet (handle, ks, parentKey, PREGETSTORAGE, DEINIT); if (splitBuildup (split, handle, parentKey) == -1) { clearError (parentKey); ELEKTRA_SET_ERROR (38, parentKey, "error in splitBuildup"); goto error; } // Check if a update is needed at all switch (elektraGetCheckUpdateNeeded (split, parentKey)) { case 0: // We don't need an update so let's do nothing keySetName (parentKey, keyName (initialParent)); elektraGlobalGet (handle, ks, parentKey, POSTGETSTORAGE, INIT); elektraGlobalGet (handle, ks, parentKey, POSTGETSTORAGE, MAXONCE); elektraGlobalGet (handle, ks, parentKey, POSTGETSTORAGE, DEINIT); splitUpdateFileName (split, handle, parentKey); keyDel (initialParent); splitDel (split); errno = errnosave; keyDel (oldError); return 0; case -1: goto error; // otherwise fall trough } // Appoint keys (some in the bypass) if (splitAppoint (split, handle, ks) == -1) { clearError (parentKey); ELEKTRA_SET_ERROR (38, parentKey, "error in splitAppoint"); goto error; } if (handle->globalPlugins[POSTGETSTORAGE][FOREACH] || handle->globalPlugins[POSTGETCLEANUP][FOREACH]) { clearError (parentKey); if (elektraGetDoUpdateWithGlobalHooks (NULL, split, NULL, parentKey, initialParent, FIRST) == -1) { goto error; } else { copyError (parentKey, oldError); } keySetName (parentKey, keyName (initialParent)); if (splitGet (split, parentKey, handle) == -1) { ELEKTRA_ADD_WARNING (108, parentKey, keyName (ksCurrent (ks))); // continue, because sizes are already updated } ksClear (ks); splitMerge (split, ks); clearError (parentKey); if (elektraGetDoUpdateWithGlobalHooks (handle, split, ks, parentKey, initialParent, LAST) == -1) { goto error; } else { copyError (parentKey, oldError); } } else { /* Now do the real updating, but not for bypassed keys in split->size-1 */ clearError (parentKey); if (elektraGetDoUpdate (split, parentKey) == -1) { goto error; } else { copyError (parentKey, oldError); } /* Now post-process the updated keysets */ if (splitGet (split, parentKey, handle) == -1) { ELEKTRA_ADD_WARNING (108, parentKey, keyName (ksCurrent (ks))); // continue, because sizes are already updated } /* We are finished, now just merge everything to returned */ ksClear (ks); splitMerge (split, ks); } elektraGlobalGet (handle, ks, parentKey, POSTGETSTORAGE, INIT); elektraGlobalGet (handle, ks, parentKey, POSTGETSTORAGE, MAXONCE); elektraGlobalGet (handle, ks, parentKey, POSTGETSTORAGE, DEINIT); ksRewind (ks); keySetName (parentKey, keyName (initialParent)); splitUpdateFileName (split, handle, parentKey); keyDel (initialParent); keyDel (oldError); splitDel (split); errno = errnosave; return 1; error: keySetName (parentKey, keyName (initialParent)); elektraGlobalError (handle, ks, parentKey, POSTGETSTORAGE, INIT); elektraGlobalError (handle, ks, parentKey, POSTGETSTORAGE, MAXONCE); elektraGlobalError (handle, ks, parentKey, POSTGETSTORAGE, DEINIT); keySetName (parentKey, keyName (initialParent)); if (handle) splitUpdateFileName (split, handle, parentKey); keyDel (initialParent); keyDel (oldError); splitDel (split); errno = errnosave; return -1; }
/** @brief Set keys in an atomic and universal way. * * @pre kdbGet() must be called before kdbSet(): * - initially (after kdbOpen()) * - after conflict errors in kdbSet(). * * @pre The @p returned KeySet must be a valid KeySet, e.g. constructed * with ksNew(). * * @pre The @p parentKey Key must be a valid Key, e.g. constructed with * keyNew(). * * If you pass NULL on any parameter kdbSet() will fail immediately without doing anything. * * With @p parentKey you can give an hint which part of the given keyset * is of interest for you. Then you promise to only modify or * remove keys below this key. All others would be passed back * as they were retrieved by kdbGet(). * * @par Errors * If some error occurs: * - kdbSet() will leave the KeySet's * internal cursor on the key that generated the error. * - Error information will be written into the metadata of * the parent key. * - None of the keys are actually committed in this situation, i.e. no * configuration file will be modified. * * In case of errors you should present the error message to the user and let the user decide what * to do. Possible solutions are: * - remove the problematic key and use kdbSet() again (for validation or type errors) * - change the value of the problematic key and use kdbSet() again (for validation errors) * - do a kdbGet() (for conflicts, i.e. error 30) and then * - set the same keyset again (in favour of what was set by this user) * - drop the old keyset (in favour of what was set from another application) * - merge the original, your own and the other keyset * - export the configuration into a file (for unresolvable errors) * - repeat the same kdbSet might be of limited use if the user does * not explicitly request it, because temporary * errors are rare and its unlikely that they fix themselves * (e.g. disc full, permission problems) * * @par Optimization * Each key is checked with keyNeedSync() before being actually committed. * If no key of a backend needs to be synced * any affairs to backends are omitted and 0 is returned. * * @snippet kdbset.c set * * showElektraErrorDialog() and doElektraMerge() need to be implemented * by the user of Elektra. For doElektraMerge a 3-way merge algorithm exists in * libelektra-tools. * * @param handle contains internal information of @link kdbOpen() opened @endlink key database * @param ks a KeySet which should contain changed keys, otherwise nothing is done * @param parentKey is used to add warnings and set an error * information. Additionally, its name is an hint which keys * should be committed (it is possible that more are changed). * - cascading keys (starting with /) will set the path in all namespaces * - / will commit all keys * - metanames will be rejected (error 104) * - empty/invalid (error 105) * @retval 1 on success * @retval 0 if nothing had to be done, no changes in KDB * @retval -1 on failure, no changes in KDB * @see keyNeedSync() * @see ksCurrent() contains the error key * @see kdbOpen() and kdbGet() that must be called first * @see kdbClose() that must be called afterwards * @ingroup kdb */ int kdbSet (KDB * handle, KeySet * ks, Key * parentKey) { elektraNamespace ns = keyGetNamespace (parentKey); if (ns == KEY_NS_NONE) { return -1; } Key * oldError = keyNew (keyName (parentKey), KEY_END); copyError (oldError, parentKey); if (ns == KEY_NS_META) { clearError (parentKey); // clear previous error to set new one ELEKTRA_SET_ERRORF (104, parentKey, "metakey with name \"%s\" passed to kdbSet", keyName (parentKey)); keyDel (oldError); return -1; } if (ns == KEY_NS_EMPTY) { ELEKTRA_ADD_WARNING (105, parentKey, "invalid key name passed to kdbSet"); } if (!handle || !ks) { clearError (parentKey); // clear previous error to set new one ELEKTRA_SET_ERROR (37, parentKey, "handle or ks null pointer"); keyDel (oldError); return -1; } int errnosave = errno; Key * initialParent = keyDup (parentKey); ELEKTRA_LOG ("now in new kdbSet (%s) %p %zd", keyName (parentKey), (void *)handle, ksGetSize (ks)); elektraGlobalSet (handle, ks, parentKey, PRESETSTORAGE, INIT); elektraGlobalSet (handle, ks, parentKey, PRESETSTORAGE, MAXONCE); elektraGlobalSet (handle, ks, parentKey, PRESETSTORAGE, DEINIT); ELEKTRA_LOG ("after presetstorage maxonce(%s) %p %zd", keyName (parentKey), (void *)handle, ksGetSize (ks)); Split * split = splitNew (); Key * errorKey = 0; if (splitBuildup (split, handle, parentKey) == -1) { clearError (parentKey); // clear previous error to set new one ELEKTRA_SET_ERROR (38, parentKey, "error in splitBuildup"); goto error; } // 1.) Search for syncbits int syncstate = splitDivide (split, handle, ks); if (syncstate == -1) { clearError (parentKey); // clear previous error to set new one ELEKTRA_SET_ERROR (8, parentKey, keyName (ksCurrent (ks))); goto error; } ELEKTRA_ASSERT (syncstate == 0 || syncstate == 1, "syncstate not 0 or 1, but %d", syncstate); // 2.) Search for changed sizes syncstate |= splitSync (split); ELEKTRA_ASSERT (syncstate <= 1, "syncstate not equal or below 1, but %d", syncstate); if (syncstate != 1) { /* No update is needed */ keySetName (parentKey, keyName (initialParent)); if (syncstate < 0) clearError (parentKey); // clear previous error to set new one if (syncstate == -1) { ELEKTRA_SET_ERROR (107, parentKey, "Assert failed: invalid namespace"); } else if (syncstate < -1) { ELEKTRA_SET_ERROR (107, parentKey, keyName (split->parents[-syncstate - 2])); } keyDel (initialParent); splitDel (split); errno = errnosave; keyDel (oldError); return syncstate == 0 ? 0 : -1; } ELEKTRA_ASSERT (syncstate == 1, "syncstate not 1, but %d", syncstate); splitPrepare (split); clearError (parentKey); // clear previous error to set new one if (elektraSetPrepare (split, parentKey, &errorKey, handle->globalPlugins) == -1) { goto error; } else { // no error, restore old error copyError (parentKey, oldError); } keySetName (parentKey, keyName (initialParent)); elektraGlobalSet (handle, ks, parentKey, PRECOMMIT, INIT); elektraGlobalSet (handle, ks, parentKey, PRECOMMIT, MAXONCE); elektraGlobalSet (handle, ks, parentKey, PRECOMMIT, DEINIT); elektraSetCommit (split, parentKey); elektraGlobalSet (handle, ks, parentKey, COMMIT, INIT); elektraGlobalSet (handle, ks, parentKey, COMMIT, MAXONCE); elektraGlobalSet (handle, ks, parentKey, COMMIT, DEINIT); splitUpdateSize (split); keySetName (parentKey, keyName (initialParent)); elektraGlobalSet (handle, ks, parentKey, POSTCOMMIT, INIT); elektraGlobalSet (handle, ks, parentKey, POSTCOMMIT, MAXONCE); elektraGlobalSet (handle, ks, parentKey, POSTCOMMIT, DEINIT); for (size_t i = 0; i < ks->size; ++i) { // remove all flags from all keys clear_bit (ks->array[i]->flags, KEY_FLAG_SYNC); } keySetName (parentKey, keyName (initialParent)); keyDel (initialParent); splitDel (split); keyDel (oldError); errno = errnosave; return 1; error: keySetName (parentKey, keyName (initialParent)); elektraGlobalError (handle, ks, parentKey, PREROLLBACK, INIT); elektraGlobalError (handle, ks, parentKey, PREROLLBACK, MAXONCE); elektraGlobalError (handle, ks, parentKey, PREROLLBACK, DEINIT); elektraSetRollback (split, parentKey); if (errorKey) { Key * found = ksLookup (ks, errorKey, 0); if (!found) { ELEKTRA_ADD_WARNING (82, parentKey, keyName (errorKey)); } } keySetName (parentKey, keyName (initialParent)); elektraGlobalError (handle, ks, parentKey, POSTROLLBACK, INIT); elektraGlobalError (handle, ks, parentKey, POSTROLLBACK, MAXONCE); elektraGlobalError (handle, ks, parentKey, POSTROLLBACK, DEINIT); keySetName (parentKey, keyName (initialParent)); keyDel (initialParent); splitDel (split); errno = errnosave; keyDel (oldError); return -1; }
int elektraCryptoGcryDecrypt (elektraCryptoHandle * handle, Key * k, Key * errorKey) { gcry_error_t gcry_err; // parse salt length from crypto payload kdb_unsigned_long_t saltLen = 0; if (CRYPTO_PLUGIN_FUNCTION (getSaltFromPayload) (errorKey, k, NULL, &saltLen) != 1) { return -1; // error set by CRYPTO_PLUGIN_FUNCTION(getSaltFromPayload)() } saltLen += sizeof (kdb_unsigned_long_t); // set payload pointer const kdb_octet_t * payload = ((kdb_octet_t *) keyValue (k)) + saltLen + ELEKTRA_CRYPTO_MAGIC_NUMBER_LEN; const size_t payloadLen = keyGetValueSize (k) - saltLen - ELEKTRA_CRYPTO_MAGIC_NUMBER_LEN; // plausibility check if (payloadLen % ELEKTRA_CRYPTO_GCRY_BLOCKSIZE != 0) { ELEKTRA_SET_ERROR (ELEKTRA_ERROR_CRYPTO_DECRYPT_FAIL, errorKey, "value length is not a multiple of the block size"); return -1; } // prepare buffer for plain text output and crypto operations kdb_octet_t * output = elektraMalloc (payloadLen); if (!output) { ELEKTRA_SET_ERROR (87, errorKey, "Memory allocation failed"); return -1; } // initialize crypto header data kdb_unsigned_long_t contentLen = 0; kdb_octet_t flags = ELEKTRA_CRYPTO_FLAG_NONE; // in-place decryption memcpy (output, payload, payloadLen); gcry_err = gcry_cipher_decrypt (*handle, output, payloadLen, NULL, 0); if (gcry_err != 0) { ELEKTRA_SET_ERRORF (ELEKTRA_ERROR_CRYPTO_DECRYPT_FAIL, errorKey, "Decryption failed because: %s", gcry_strerror (gcry_err)); memset (output, 0, payloadLen); elektraFree (output); return -1; } // restore the header data memcpy (&flags, output, sizeof (flags)); memcpy (&contentLen, output + sizeof (flags), sizeof (contentLen)); const kdb_octet_t * data = output + ELEKTRA_CRYPTO_GCRY_BLOCKSIZE; const size_t dataLen = payloadLen - ELEKTRA_CRYPTO_GCRY_BLOCKSIZE; // validate restored content length if (contentLen > dataLen) { ELEKTRA_SET_ERROR ( ELEKTRA_ERROR_CRYPTO_DECRYPT_FAIL, errorKey, "restored content length is bigger than the available amount of decrypted data. The header is possibly corrupted."); memset (output, 0, payloadLen); elektraFree (output); return -1; } // restore the key to its original status if ((flags & ELEKTRA_CRYPTO_FLAG_STRING) == ELEKTRA_CRYPTO_FLAG_STRING && contentLen > 0) { keySetString (k, (const char *) data); } else if ((flags & ELEKTRA_CRYPTO_FLAG_NULL) == ELEKTRA_CRYPTO_FLAG_NULL || contentLen == 0) { keySetBinary (k, NULL, 0); } else { keySetBinary (k, data, contentLen); } memset (output, 0, payloadLen); elektraFree (output); return 1; }
int elektraCryptoGcryEncrypt (elektraCryptoHandle * handle, Key * k, Key * errorKey) { size_t outputLen; gcry_error_t gcry_err; // prepare the salt for payload output kdb_unsigned_long_t saltLen = 0; kdb_octet_t * salt = NULL; if (CRYPTO_PLUGIN_FUNCTION (getSaltFromMetakey) (errorKey, k, &salt, &saltLen) != 1) { return -1; // error set by CRYPTO_PLUGIN_FUNCTION(getSaltFromMetakey)() } // remove salt as metakey because it will be encoded into the crypto payload keySetMeta (k, ELEKTRA_CRYPTO_META_SALT, NULL); // prepare the crypto header data const kdb_octet_t * content = keyValue (k); const kdb_unsigned_long_t contentLen = keyGetValueSize (k); kdb_octet_t flags; switch (keyIsString (k)) { case 1: // string flags = ELEKTRA_CRYPTO_FLAG_STRING; break; case -1: // NULL pointer flags = ELEKTRA_CRYPTO_FLAG_NULL; break; default: // binary flags = ELEKTRA_CRYPTO_FLAG_NONE; break; } // prepare buffer for cipher text output // NOTE the header goes into the first block if (contentLen % ELEKTRA_CRYPTO_GCRY_BLOCKSIZE == 0) { outputLen = (contentLen / ELEKTRA_CRYPTO_GCRY_BLOCKSIZE) + 1; } else { outputLen = (contentLen / ELEKTRA_CRYPTO_GCRY_BLOCKSIZE) + 2; } outputLen *= ELEKTRA_CRYPTO_GCRY_BLOCKSIZE; outputLen += ELEKTRA_CRYPTO_MAGIC_NUMBER_LEN; outputLen += sizeof (kdb_unsigned_long_t) + saltLen; kdb_octet_t * output = elektraMalloc (outputLen); if (!output) { ELEKTRA_SET_ERROR (87, errorKey, "Memory allocation failed"); elektraFree (salt); return -1; } kdb_octet_t * current = output; // output of the magic number memcpy (current, ELEKTRA_CRYPTO_MAGIC_NUMBER, ELEKTRA_CRYPTO_MAGIC_NUMBER_LEN); current += ELEKTRA_CRYPTO_MAGIC_NUMBER_LEN; // encode the salt into the crypto payload memcpy (current, &saltLen, sizeof (kdb_unsigned_long_t)); current += sizeof (kdb_unsigned_long_t); memcpy (current, salt, saltLen); current += saltLen; // encrypt the header (1st block) using gcrypt's in-place encryption memcpy (current, &flags, sizeof (flags)); memcpy (current + sizeof (flags), &contentLen, sizeof (contentLen)); gcry_err = gcry_cipher_encrypt (*handle, current, ELEKTRA_CRYPTO_GCRY_BLOCKSIZE, NULL, 0); if (gcry_err != 0) { ELEKTRA_SET_ERRORF (ELEKTRA_ERROR_CRYPTO_ENCRYPT_FAIL, errorKey, "Encryption failed because: %s", gcry_strerror (gcry_err)); memset (output, 0, outputLen); elektraFree (output); elektraFree (salt); return -1; } current += ELEKTRA_CRYPTO_GCRY_BLOCKSIZE; // encrypt the value using gcrypt's in-place encryption const size_t dataLen = outputLen - ELEKTRA_CRYPTO_GCRY_BLOCKSIZE - sizeof (kdb_unsigned_long_t) - saltLen - ELEKTRA_CRYPTO_MAGIC_NUMBER_LEN; if (contentLen) memcpy (current, content, contentLen); gcry_err = gcry_cipher_encrypt (*handle, current, dataLen, NULL, 0); if (gcry_err != 0) { ELEKTRA_SET_ERRORF (ELEKTRA_ERROR_CRYPTO_ENCRYPT_FAIL, errorKey, "Encryption failed because: %s", gcry_strerror (gcry_err)); memset (output, 0, outputLen); elektraFree (output); elektraFree (salt); return -1; } // write back the cipher text to the key keySetBinary (k, output, outputLen); memset (output, 0, outputLen); elektraFree (output); elektraFree (salt); return 1; }
int elektraCryptoGcryHandleCreate (elektraCryptoHandle ** handle, KeySet * config, Key * errorKey, Key * masterKey, Key * k, const enum ElektraCryptoOperation op) { gcry_error_t gcry_err; unsigned char keyBuffer[64], ivBuffer[64]; size_t keyLength, ivLength; (*handle) = NULL; // retrieve/derive the cryptographic material Key * key = keyNew (0); Key * iv = keyNew (0); switch (op) { case ELEKTRA_CRYPTO_ENCRYPT: if (getKeyIvForEncryption (config, errorKey, masterKey, k, key, iv) != 1) { keyDel (key); keyDel (iv); return -1; } break; case ELEKTRA_CRYPTO_DECRYPT: if (getKeyIvForDecryption (config, errorKey, masterKey, k, key, iv) != 1) { keyDel (key); keyDel (iv); return -1; } break; default: // not supported keyDel (key); keyDel (iv); return -1; } keyLength = keyGetBinary (key, keyBuffer, sizeof (keyBuffer)); ivLength = keyGetBinary (iv, ivBuffer, sizeof (ivBuffer)); // create the handle (*handle) = elektraMalloc (sizeof (elektraCryptoHandle)); if (*handle == NULL) { memset (keyBuffer, 0, sizeof (keyBuffer)); memset (ivBuffer, 0, sizeof (ivBuffer)); keyDel (key); keyDel (iv); ELEKTRA_SET_ERROR (87, errorKey, "Memory allocation failed"); return -1; } if ((gcry_err = gcry_cipher_open (*handle, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC, 0)) != 0) { goto error; } if ((gcry_err = gcry_cipher_setkey (**handle, keyBuffer, keyLength)) != 0) { goto error; } if ((gcry_err = gcry_cipher_setiv (**handle, ivBuffer, ivLength)) != 0) { goto error; } memset (keyBuffer, 0, sizeof (keyBuffer)); memset (ivBuffer, 0, sizeof (ivBuffer)); keyDel (key); keyDel (iv); return 1; error: memset (keyBuffer, 0, sizeof (keyBuffer)); memset (ivBuffer, 0, sizeof (ivBuffer)); ELEKTRA_SET_ERRORF (ELEKTRA_ERROR_CRYPTO_CONFIG_FAULT, errorKey, "Failed to create handle because: %s", gcry_strerror (gcry_err)); gcry_cipher_close (**handle); elektraFree (*handle); (*handle) = NULL; keyDel (key); keyDel (iv); return -1; }