static void testwritevalidemptycol (const char * file) { Key * parentKey = keyNew ("user/tests/csvstorage", KEY_VALUE, srcdir_file (file), KEY_END); KeySet * conf = ksNew (20, keyNew ("system/delimiter", KEY_VALUE, ";", KEY_END), keyNew ("system/header", KEY_VALUE, "colname", KEY_END), KS_END); KeySet * ks = ksNew (0, KS_END); PLUGIN_OPEN ("csvstorage"); succeed_if (plugin->kdbGet (plugin, ks, parentKey) > 0, "call to kdbGet was not successful"); keySetString (parentKey, elektraFilename ()); succeed_if (plugin->kdbSet (plugin, ks, parentKey) >= 0, "error: couldn't write data"); ksDel (ks); keyDel (parentKey); PLUGIN_CLOSE (); }
static void test_lookupNoascading () { printf ("Test lookup without cascading\n"); Key * specKey = keyNew ("/abc", KEY_CASCADING_NAME, KEY_END); Key * d = keyDup (specKey); keySetString (d, "dup"); succeed_if_same_string (keyName (specKey), "/abc"); succeed_if_same_string (keyName (d), "/abc"); succeed_if (!keyCmp (d, specKey), "comparision to duplicate failed"); succeed_if_same_string (keyName (d), "/abc"); succeed_if_same_string (keyName (specKey), "/abc"); KeySet * ks = ksNew (20, d, KS_END); Key * k = ksLookup (ks, specKey, KDB_O_NOCASCADING); succeed_if_same_string (keyName (specKey), "/abc"); succeed_if (k != 0, "did not find cascading key"); succeed_if (k != specKey, "should not be specKey"); succeed_if (k == d, "should be dup key"); Key * a = keyNew (keyName (specKey), KEY_CASCADING_NAME, KEY_VALUE, "a", KEY_END); ksAppendKey (ks, a); for (int i = 0; i < 5; ++i) { k = ksLookup (ks, specKey, KDB_O_NOCASCADING); succeed_if (keyGetNameSize (specKey) == 5, "size of spec key wrong"); succeed_if_same_string (keyName (specKey), "/abc"); succeed_if (k != 0, "did not find cascading key"); succeed_if (k != specKey, "should not be specKey"); succeed_if (k == a, "should be dup key"); // search without cascading k = ksLookup (ks, specKey, 0); succeed_if (keyGetNameSize (specKey) == 5, "size of spec key wrong"); succeed_if_same_string (keyName (specKey), "/abc"); succeed_if (k != 0, "did not find cascading key"); succeed_if (k != specKey, "should not be specKey"); succeed_if (k == a, "should be dup key"); } ksDel (ks); keyDel (specKey); }
// TODO: this is very similar to elektraKeyAppendMetaLine in keytometa static int elektraKeyAppendLine (Key *target, const char *line) { if (!target) return 0; if (!line) return 0; char *buffer = elektraMalloc (keyGetValueSize(target) + strlen (line) + 1); if (!buffer) return 0; keyGetString(target, buffer, keyGetValueSize(target)); strcat (buffer, "\n"); strncat (buffer, line, strlen (line)); keySetString(target, buffer); elektraFree (buffer); return keyGetValueSize(target); }
static int elektraResolveFilename (Key * parentKey, ElektraResolveTempfile tmpFile) { int rc = 0; void * handle = elektraInvokeOpen ("resolver", 0, 0); if (!handle) { rc = -1; goto RESOLVE_FAILED; } ElektraResolved * resolved = NULL; typedef ElektraResolved * (*resolveFileFunc) (elektraNamespace, const char *, ElektraResolveTempfile, Key *); resolveFileFunc resolveFunc = *(resolveFileFunc *) elektraInvokeGetFunction (handle, "filename"); if (!resolveFunc) { rc = -1; goto RESOLVE_FAILED; } typedef void (*freeHandleFunc) (ElektraResolved *); freeHandleFunc freeHandle = *(freeHandleFunc *) elektraInvokeGetFunction (handle, "freeHandle"); if (!freeHandle) { rc = -1; goto RESOLVE_FAILED; } resolved = resolveFunc (keyGetNamespace (parentKey), keyString (parentKey), tmpFile, parentKey); if (!resolved) { rc = -1; goto RESOLVE_FAILED; } else { keySetString (parentKey, resolved->fullPath); freeHandle (resolved); } RESOLVE_FAILED: elektraInvokeClose (handle, 0); return rc; }
static void test_keySetString (const size_t storagePlugin, const char * tmpFile) { Key * parentKey = keyNew (TEST_ROOT_KEY, KEY_VALUE, tmpFile, KEY_END); open_storage_plugin (storagePlugin); Plugin * plugin = plugins[storagePlugin]; KeySet * ks = metaTestKeySet (); const char * name = "user/tests/storage/specialkey"; const char * value = "special value"; size_t realValueSize = elektraStrLen (value); Key * key = keyNew (name, KEY_VALUE, value, KEY_END); ksAppendKey (ks, key); succeed_if (plugin->kdbSet (plugin, ks, parentKey) == 1, "kdbSet was not successful"); succeed_if (plugin->kdbGet (plugin, ks, parentKey) == 1, "kdbGet was not successful"); Key * found = ksLookupByName (ks, name, KDB_O_POP); succeed_if (found, "did not find key"); // now set a new key string to the Key _after_ kdbGet const char * newValue = "some new special value"; size_t newValueSize = elektraStrLen (newValue); succeed_if (keySetString (found, newValue) == (ssize_t) newValueSize, "Key string could not be set"); ksAppendKey (ks, found); succeed_if (plugin->kdbSet (plugin, ks, parentKey) == 1, "kdbSet was not successful"); succeed_if (plugin->kdbGet (plugin, ks, parentKey) == 1, "kdbGet was not successful"); found = ksLookupByName (ks, name, 0); succeed_if (found, "did not find key"); ssize_t apiValueSize = keyGetValueSize (found); char * apiValue = elektraMalloc (apiValueSize); succeed_if (keyGetString (found, apiValue, apiValueSize) == (ssize_t) newValueSize, "Key string has wrong size"); succeed_if (elektraStrNCmp (value, apiValue, realValueSize) != 0, "Key string value is wrong"); succeed_if (elektraStrNCmp (newValue, apiValue, newValueSize) == 0, "Key string value is wrong"); elektraFree (apiValue); keyDel (parentKey); ksDel (ks); closeStoragePlugin (storagePlugin); }
static int convertToKey(augeas *handle, const char *treePath, void *data) { struct KeyConversion *conversionData = (struct KeyConversion *) data; int result = 0; const char *value = 0; result = aug_get (handle, treePath, &value); if (result < 0) return result; Key *key = createKeyFromPath (conversionData->parentKey, treePath); /* fill key values */ keySetString (key, value); conversionData->currentOrder++; keySetOrderMeta (key, conversionData->currentOrder); result = ksAppendKey (conversionData->ks, key); return result; }
static int iniKeyToElektraKey (void *vconfig, const char *section, const char *name, const char *value) { Configuration *config = (Configuration *)vconfig; Key *appendKey = keyDup (config->parentKey); if (section) { keyAddBaseName(appendKey, section); } keyAddBaseName (appendKey, name); writeCommentToMeta (config, appendKey); keySetString (appendKey, value); ksAppendKey (config->result, appendKey); return 1; }
static void test_file_crypto_operations (void) { Plugin * plugin = NULL; Key * parentKey = keyNew ("system", KEY_END); KeySet * modules = ksNew (0, KS_END); KeySet * config = newPluginConfiguration (); elektraModulesInit (modules, 0); plugin = elektraPluginOpen (PLUGIN_NAME, modules, config, 0); succeed_if (plugin, "failed to open plugin handle"); if (plugin) { KeySet * data = ksNew (0, KS_END); const char * tmpFile = elektraFilename (); if (tmpFile) { // prepare test file to be encrypted writeTestFile (tmpFile); keySetString (parentKey, tmpFile); // try to encrypt the file succeed_if (plugin->kdbSet (plugin, data, parentKey) == 1, "kdb set failed"); succeed_if (isTestFileCorrect (tmpFile) == -1, "file content did not change during encryption"); // try to decrypt the file again (simulating the pregetstorage call) succeed_if (plugin->kdbGet (plugin, data, parentKey) == 1, "kdb get (pregetstorage) failed"); succeed_if (isTestFileCorrect (keyString (parentKey)) == 1, "file content could not be restored during decryption"); // a second call to kdb get (the postgetstorage call) should re-encrypt the file again succeed_if (plugin->kdbGet (plugin, data, parentKey) == 1, "kdb get (postgetstorage) failed"); succeed_if (isTestFileCorrect (tmpFile) == -1, "postgetstorage did not encrypt the file again"); remove (tmpFile); } ksDel (data); elektraPluginClose (plugin, 0); } elektraModulesClose (modules, 0); ksDel (modules); keyDel (parentKey); }
void test_json (const char * fileName, KeySet * compareKeySet, KeySet * conf) { printf ("Test json with %s\n", srcdir_file (fileName)); Plugin * plugin = elektraPluginOpen ("yajl", modules, conf, 0); exit_if_fail (plugin != 0, "could not open plugin"); // printf ("Test with %s\n", srcdir_file(fileName)); Key * parentKey = keyNew ("user/tests/yajl", KEY_VALUE, srcdir_file (fileName), KEY_END); KeySet * keys = ksNew (0, KS_END); succeed_if (plugin->kdbGet (plugin, keys, parentKey) == 1, "kdbGet was not successful"); succeed_if (output_error (parentKey), "error in kdbGet"); succeed_if (output_warnings (parentKey), "warnings in kdbGet"); /* output_keyset(keys); output_keyset(compareKeySet); */ compare_keyset (keys, compareKeySet); keySetString (parentKey, elektraFilename ()); // printf("File name is: %s\n", keyString(parentKey)); succeed_if (plugin->kdbSet (plugin, keys, parentKey) == 1, "kdbSet was not successful"); succeed_if (output_error (parentKey), "error in kdbSet"); succeed_if (output_warnings (parentKey), "warnings in kdbSet"); succeed_if (compare_line_files (srcdir_file (fileName), keyString (parentKey)), "files do not match as expected"); elektraUnlink (keyString (parentKey)); /* printf ("The keys we read out are:\n"); output_keyset(keys); printf ("The keys we compared it with:\n"); output_keyset(compareKeySet); */ keyDel (parentKey); ksDel (keys); ksDel (compareKeySet); elektraPluginClose (plugin, 0); }
void test_ro() { Key *key; key = keyNew(KEY_END); key->flags |= KEY_FLAG_RO; succeed_if (keySetString(key, "a") == -1, "read only string, not allowed to set"); succeed_if (keySetBinary(key, "a", 2) == -1, "read only string, not allowed to set"); succeed_if (keySetName(key, "user") == -1, "read only string, not allowed to set"); succeed_if (keySetMeta(key, "meta", "value") == -1, "read only string, not allowed to set"); keyDel (key); key = keyNew(KEY_END); succeed_if (keySetMeta(key, "meta", "value") == sizeof("value"), "could not set meta"); // TODO check if RO keyDel (key); }
void elektraMetaArrayAdd (Key * key, const char * metaName, const char * value) { const Key * meta = keyGetMeta (key, metaName); Key * arrayKey; if (!meta) { keySetMeta (key, metaName, "#0"); arrayKey = keyDup (keyGetMeta (key, metaName)); keySetString (arrayKey, 0); keyAddBaseName (arrayKey, "#"); } else { arrayKey = keyDup (meta); keyAddBaseName (arrayKey, keyString (meta)); } elektraArrayIncName (arrayKey); keySetMeta (key, keyName (arrayKey), value); keySetMeta (key, metaName, keyBaseName (arrayKey)); keyDel (arrayKey); }
static int elektraYajlParseString (void * ctx, const unsigned char * stringVal, yajl_size_type stringLen) { KeySet * ks = (KeySet *)ctx; elektraYajlIncrementArrayEntry (ks); Key * current = ksCurrent (ks); unsigned char delim = stringVal[stringLen]; char * stringValue = (char *)stringVal; stringValue[stringLen] = '\0'; #ifdef ELEKTRA_YAJL_VERBOSE printf ("elektraYajlParseString %s %d\n", stringVal, stringLen); #endif keySetString (current, stringValue); // restore old character in buffer stringValue[stringLen] = delim; return 1; }
static void test_simpleCutRestoreOnSet () { Key *parentKey = keyNew ("user/tests/rename", KEY_END); Key *parentKeyCopy = keyDup(parentKey); KeySet *conf = ksNew (20, keyNew ("system/cut", KEY_VALUE, "will/be/stripped", KEY_END), KS_END); PLUGIN_OPEN("rename"); KeySet *ks = createSimpleTestKeys(); ksAppendKey(ks, parentKey); succeed_if(plugin->kdbGet (plugin, ks, parentKey) >= 1, "call to kdbGet was not successful"); succeed_if(output_error (parentKey), "error in kdbGet"); succeed_if(output_warnings (parentKey), "warnings in kdbGet"); succeed_if(plugin->kdbSet (plugin, ks, parentKey) >= 1, "call to kdbSet was not successful"); succeed_if(output_error (parentKey), "error in kdbSet"); succeed_if(output_warnings (parentKey), "warnings in kdbSet"); /* test that the keys have been correctly restored */ KeySet *expected = createSimpleTestKeys(); /* the parent key is restored from user/tests/rename/will/be/stripped * and therefore will have its key value */ keySetString (parentKeyCopy, "value3"); ksAppendKey (expected, parentKeyCopy); compareKeySets (ks, expected); ksDel(expected); ksDel(ks); /* * this has to be done because the parentKey is not * part of ks anymore due to renaming */ keyDel(parentKey); PLUGIN_CLOSE (); }
/** * Opens the internal backend that indicates that a backend * is missing at that place. * * @return the fresh allocated backend or 0 if no memory */ Backend* elektraBackendOpenMissing(Key *mp) { Backend *backend = elektraBackendAllocate(); Plugin *plugin = elektraPluginMissing(); if (!plugin) { /* Could not allocate plugin */ elektraFree(backend); return 0; } backend->getplugins[0] = plugin; backend->setplugins[0] = plugin; plugin->refcounter = 2; keySetString (mp, "missing"); backend->mountpoint = mp; keyIncRef(backend->mountpoint); return backend; }
void testRoundTrip (const char * fileName) { Key * parentKey = keyNew ("user/tests/file", KEY_VALUE, srcdir_file (fileName), KEY_END); KeySet * conf = ksNew (0, KS_END); PLUGIN_OPEN ("file"); KeySet * ks = ksNew (0, KS_END); succeed_if (plugin->kdbGet (plugin, ks, parentKey) >= 1, "call to kdbGet was not successful"); keySetString (parentKey, elektraFilename ()); succeed_if (plugin->kdbSet (plugin, ks, parentKey) == 1, "call to kdbSet was not successful"); succeed_if (compare_line_files (srcdir_file (fileName), keyString (parentKey)), "files do not match as expected"); ksDel (ks); keyDel (parentKey); PLUGIN_CLOSE (); }
static void test_file_signature_operations (void) { Plugin * plugin = NULL; Key * parentKey = keyNew ("system", KEY_END); KeySet * modules = ksNew (0, KS_END); KeySet * config = newPluginConfiguration (); elektraModulesInit (modules, 0); plugin = elektraPluginOpen (PLUGIN_NAME, modules, config, 0); succeed_if (plugin, "failed to open plugin handle"); if (plugin) { KeySet * data = ksNew (0, KS_END); const char * tmpFile = elektraFilename (); if (tmpFile) { // prepare test file to be encrypted writeTestFile (tmpFile); keySetString (parentKey, tmpFile); // try to encrypt the file succeed_if (plugin->kdbSet (plugin, data, parentKey) == 1, "kdb set failed"); succeed_if (isTestFileCorrect (tmpFile) == -1, "file content did not change during encryption"); // try to decrypt/verify the file succeed_if (plugin->kdbGet (plugin, data, parentKey) == 1, "kdb get failed"); remove (tmpFile); } ksDel (data); elektraPluginClose (plugin, 0); } elektraModulesClose (modules, 0); ksDel (modules); keyDel (parentKey); }
static void test_BlockresolverWrite (char * fileName, char * compareName) { FILE * fin = fopen (srcdir_file (fileName), "r"); char buffer[1024]; const char * foutname = elektraFilename (); FILE * fout = fopen (foutname, "w"); while (fgets (buffer, sizeof (buffer), fin)) { fputs (buffer, fout); } fclose (fin); fclose (fout); Key * parentKey = keyNew ("system/test/blockresolver-write", KEY_VALUE, foutname, KEY_END); KeySet * conf = ksNew (10, keyNew ("system/path", KEY_VALUE, foutname, KEY_END), keyNew ("system/identifier", KEY_VALUE, "### block config", KEY_END), KS_END); KeySet * modules = ksNew (0, KS_END); KeySet * ks = ksNew (0, KS_END); elektraModulesInit (modules, 0); Plugin * resolver = elektraPluginOpen ("blockresolver", modules, ksDup (conf), 0); succeed_if (resolver->kdbGet (resolver, ks, parentKey) >= 0, "blockresolver->kdbGet failed"); Plugin * storage = elektraPluginOpen ("ini", modules, ksNew (0, KS_END), 0); succeed_if (storage->kdbGet (storage, ks, parentKey) >= 0, "storage->kdbGet failed"); keySetString (ksLookupByName (ks, "system/test/blockresolver-write/section/key", 0), "only the inside has changed"); succeed_if (storage->kdbSet (storage, ks, parentKey) >= 0, "storage->kdbSet failed"); succeed_if (resolver->kdbSet (resolver, ks, parentKey) >= 0, "blockresolver->kdbSet failed"); succeed_if (resolver->kdbSet (resolver, ks, parentKey) >= 0, "blockresolver->kdbSet failed"); succeed_if (compare_line_files (srcdir_file (compareName), foutname), "files do not match as expected"); elektraPluginClose (storage, 0); elektraPluginClose (resolver, 0); ksDel (conf); ksDel (ks); elektraModulesClose (modules, 0); ksDel (modules); keyDel (parentKey); }
/** * Creates a new Elektra key from the specified Augeas key. * If any step during key conversion fails, an error is returned * in order to prevent inconsistent keys. */ static int convertToKey (augeas * handle, const char * treePath, void * data) { struct KeyConversion * conversionData = (struct KeyConversion *)data; int result = 0; const char * value = 0; result = aug_get (handle, treePath, &value); /* we were unable to retrieve the augeas value */ if (result < 0) return result; Key * key = createKeyFromPath (conversionData->parentKey, treePath); /* fill key values */ keySetString (key, value); conversionData->currentOrder++; result = keySetOrderMeta (key, conversionData->currentOrder); /* setting the correct key order failed */ if (result < 0) return result; result = ksAppendKey (conversionData->ks, key); return result; }
static void test_intNoUpdateWithInvalidValue (void) { printf ("test no update with invalid value\n"); KeySet * conf = ksNew (0, KS_END); PLUGIN_OPEN ("internalnotification"); Key * valueKey = keyNew ("user/test/internalnotification/value", KEY_END); KeySet * ks = ksNew (1, valueKey, KS_END); int value = 123; succeed_if (internalnotificationRegisterInt (plugin, valueKey, &value) == 1, "call to elektraInternalnotificationRegisterInt was not successful"); keySetString (valueKey, "42abcd"); elektraInternalnotificationUpdateRegisteredKeys (plugin, ks); succeed_if (value == 123, "registered value was updated"); ksDel (ks); PLUGIN_CLOSE (); }
int elektraIconvGet (Plugin * handle, KeySet * returned, Key * parentKey) { Key * cur; ksRewind (returned); if (!strcmp (keyName (parentKey), "system/elektra/modules/iconv")) { KeySet * pluginConfig = ksNew (30, keyNew ("system/elektra/modules/iconv", KEY_VALUE, "iconv plugin waits for your orders", KEY_END), keyNew ("system/elektra/modules/iconv/exports", KEY_END), keyNew ("system/elektra/modules/iconv/exports/get", KEY_FUNC, elektraIconvGet, KEY_END), keyNew ("system/elektra/modules/iconv/exports/set", KEY_FUNC, elektraIconvSet, KEY_END), #include "readme_iconv.c" keyNew ("system/elektra/modules/iconv/infos/version", KEY_VALUE, PLUGINVERSION, KEY_END), KS_END); ksAppend (returned, pluginConfig); ksDel (pluginConfig); return 1; } if (!kdbbNeedsUTF8Conversion (handle)) return 0; while ((cur = ksNext (returned)) != 0) { if (keyIsString (cur)) { /* String or similar type of value */ size_t convertedDataSize = keyGetValueSize (cur); char * convertedData = elektraMalloc (convertedDataSize); memcpy (convertedData, keyString (cur), keyGetValueSize (cur)); if (kdbbUTF8Engine (handle, UTF8_FROM, &convertedData, &convertedDataSize)) { ELEKTRA_SET_ERRORF (46, parentKey, "Could not convert string %s, got result %s, encoding settings are from %s to %s", keyString (cur), convertedData, getFrom (handle), getTo (handle)); elektraFree (convertedData); return -1; } keySetString (cur, convertedData); elektraFree (convertedData); } const Key * meta = keyGetMeta (cur, "comment"); if (meta) { /* String or similar type of value */ size_t convertedDataSize = keyGetValueSize (meta); char * convertedData = elektraMalloc (convertedDataSize); memcpy (convertedData, keyString (meta), keyGetValueSize (meta)); if (kdbbUTF8Engine (handle, UTF8_FROM, &convertedData, &convertedDataSize)) { ELEKTRA_SET_ERRORF (46, parentKey, "Could not convert string %s, got result %s, encoding settings are from %s to %s", keyString (meta), convertedData, getFrom (handle), getTo (handle)); elektraFree (convertedData); return -1; } keySetMeta (cur, "comment", convertedData); elektraFree (convertedData); } } return 1; /* success */ }
static CondResult parseConditionString (const Key * meta, const Key * suffixList, Key * parentKey, Key * key, KeySet * ks, Operation op) { const char * conditionString = keyString (meta); const char * regexString1 = "(\\(((.*)?)\\))[[:space:]]*\\?"; const char * regexString2 = "\\?[[:space:]]*(\\(((.*)?)\\))"; const char * regexString3 = "[[:space:]]*:[[:space:]]*(\\(((.*)?)\\))"; regex_t regex1, regex2, regex3; CondResult ret; if ((ret = regcomp (®ex1, regexString1, REGEX_FLAGS_CONDITION))) { ELEKTRA_SET_ERROR (87, parentKey, "Couldn't compile regex: most likely out of memory"); // the regex compiles so the only // possible error would be out of // memory ksDel (ks); return ERROR; } if ((ret = regcomp (®ex2, regexString2, REGEX_FLAGS_CONDITION))) { ELEKTRA_SET_ERROR (87, parentKey, "Couldn't compile regex: most likely out of memory"); // the regex compiles so the only // possible error would be out of // memory regfree (®ex1); ksDel (ks); return ERROR; } if ((ret = regcomp (®ex3, regexString3, REGEX_FLAGS_CONDITION))) { ELEKTRA_SET_ERROR (87, parentKey, "Couldn't compile regex: most likely out of memory"); // the regex compiles so the only // possible error would be out of // memory regfree (®ex1); regfree (®ex2); ksDel (ks); return ERROR; } int subMatches = 6; regmatch_t m[subMatches]; int nomatch = regexec (®ex1, conditionString, subMatches, m, 0); if (nomatch) { ELEKTRA_SET_ERRORF (134, parentKey, "Invalid syntax: \"%s\". Check kdb info conditionals for additional information", conditionString); regfree (®ex1); regfree (®ex2); regfree (®ex3); ksDel (ks); return ERROR; } if (m[1].rm_so == -1) { ELEKTRA_SET_ERRORF (134, parentKey, "Invalid syntax: \"%s\". Check kdb info conditionals for additional information", conditionString); regfree (®ex1); regfree (®ex2); regfree (®ex3); ksDel (ks); return ERROR; } int startPos = m[1].rm_so; int endPos = m[1].rm_eo; char * condition = elektraMalloc (endPos - startPos + 1); char * thenexpr = NULL; char * elseexpr = NULL; strncpy (condition, conditionString + startPos, endPos - startPos); condition[endPos - startPos] = '\0'; nomatch = regexec (®ex2, conditionString, subMatches, m, 0); if (nomatch) { ELEKTRA_SET_ERRORF (134, parentKey, "Invalid syntax: \"%s\". Check kdb info conditionals for additional information", conditionString); regfree (®ex1); regfree (®ex2); regfree (®ex3); ksDel (ks); return ERROR; } if (m[1].rm_so == -1) { ELEKTRA_SET_ERRORF (134, parentKey, "Invalid syntax: \"%s\". Check kdb info conditionals for additional information", conditionString); regfree (®ex1); regfree (®ex2); regfree (®ex3); ksDel (ks); return ERROR; } startPos = m[1].rm_so; endPos = m[1].rm_eo; thenexpr = elektraMalloc (endPos - startPos + 1); strncpy (thenexpr, conditionString + startPos, endPos - startPos); thenexpr[endPos - startPos] = '\0'; nomatch = regexec (®ex3, conditionString, subMatches, m, 0); if (!nomatch) { if (m[1].rm_so == -1) { ELEKTRA_SET_ERRORF (134, parentKey, "Invalid syntax: \"%s\". Check kdb info conditionals for additional information", conditionString); regfree (®ex1); regfree (®ex2); regfree (®ex3); ksDel (ks); return ERROR; } thenexpr[strlen (thenexpr) - ((m[0].rm_eo - m[0].rm_so))] = '\0'; startPos = m[1].rm_so; endPos = m[1].rm_eo; elseexpr = elektraMalloc (endPos - startPos + 1); strncpy (elseexpr, conditionString + startPos, endPos - startPos); elseexpr[endPos - startPos] = '\0'; } ret = parseCondition (key, condition, suffixList, ks, parentKey); if (ret == TRUE) { if (op == ASSIGN) { const char * assign = isAssign (key, thenexpr, parentKey, ks); if (assign != NULL) { keySetString (key, assign); ret = TRUE; goto CleanUp; } else { ret = ERROR; goto CleanUp; } } else { ret = parseCondition (key, thenexpr, suffixList, ks, parentKey); if (ret == FALSE) { ELEKTRA_SET_ERRORF (135, parentKey, "Validation of Key %s: %s failed. (%s failed)", keyName (key) + strlen (keyName (parentKey)) + 1, conditionString, thenexpr); } else if (ret == ERROR) { ELEKTRA_SET_ERRORF (134, parentKey, "Invalid syntax: \"%s\". Check kdb info conditionals for additional information", thenexpr); } } } else if (ret == FALSE) { if (elseexpr) { if (op == ASSIGN) { const char * assign = isAssign (key, elseexpr, parentKey, ks); if (assign != NULL) { keySetString (key, assign); ret = TRUE; goto CleanUp; } else { ret = ERROR; goto CleanUp; } } else { ret = parseCondition (key, elseexpr, suffixList, ks, parentKey); if (ret == FALSE) { ELEKTRA_SET_ERRORF (135, parentKey, "Validation of Key %s: %s failed. (%s failed)", keyName (key) + strlen (keyName (parentKey)) + 1, conditionString, elseexpr); } else if (ret == ERROR) { ELEKTRA_SET_ERRORF ( 134, parentKey, "Invalid syntax: \"%s\". Check kdb info conditionals for additional information", elseexpr); } } } else { ret = NOEXPR; } } else if (ret == ERROR) { ELEKTRA_SET_ERRORF (134, parentKey, "Invalid syntax: \"%s\". Check kdb info conditionals for additional information", condition); } CleanUp: elektraFree (condition); elektraFree (thenexpr); if (elseexpr) elektraFree (elseexpr); regfree (®ex1); regfree (®ex2); regfree (®ex3); ksDel (ks); return ret; }
static CondResult evalCondition (const Key * curKey, const char * leftSide, Comparator cmpOp, const char * rightSide, const char * condition, const Key * suffixList, KeySet * ks, Key * parentKey) { char * lookupName = NULL; char * compareTo = NULL; Key * key; int len; long result = 0; if (rightSide) { if (rightSide[0] == '\'') { // right side of the statement is a literal enclosed by '' char * endPos = strchr (rightSide + 1, '\''); if (!endPos) { result = ERROR; goto Cleanup; } if (elektraRealloc ((void **) &compareTo, endPos - rightSide) < 0) { ELEKTRA_SET_ERROR (87, parentKey, "Out of memory"); result = ERROR; goto Cleanup; } memset (compareTo, 0, endPos - rightSide); strncat (compareTo, rightSide + 1, endPos - rightSide - 1); } else if (rightSide && elektraStrLen (rightSide) > 1) { // not a literal, it has to be a key if (rightSide[0] == '@') len = keyGetNameSize (parentKey) + elektraStrLen (rightSide); else if (!strncmp (rightSide, "..", 2) || (rightSide[0] == '.')) len = keyGetNameSize (curKey) + elektraStrLen (rightSide); else len = elektraStrLen (rightSide); if (elektraRealloc ((void **) &lookupName, len) < 0) { ELEKTRA_SET_ERROR (87, parentKey, "Out of memory"); result = ERROR; goto Cleanup; } if (rightSide[0] == '@') snprintf (lookupName, len, "%s/%s", keyName (parentKey), rightSide + 1); else if (rightSide[0] == '.') // either starts with . or .., doesn't matter at this point snprintf (lookupName, len, "%s/%s", keyName (curKey), rightSide); else snprintf (lookupName, len, "%s", rightSide); key = ksLookupByName (ks, lookupName, 0); if (!key) { if (!keyGetMeta (parentKey, "error")) { ELEKTRA_SET_ERRORF (133, parentKey, "Key %s not found but is required for the evaluation of %s", lookupName, condition); } result = FALSE; goto Cleanup; } if (elektraRealloc ((void **) &compareTo, keyGetValueSize (key)) < 0) { ELEKTRA_SET_ERROR (87, parentKey, "Out of memory"); result = ERROR; goto Cleanup; } strcpy (compareTo, keyString (key)); } } if (leftSide[0] == '@') len = keyGetNameSize (parentKey) + elektraStrLen (leftSide); else if (!strncmp (leftSide, "..", 2) || (leftSide[0] == '.')) len = keyGetNameSize (curKey) + elektraStrLen (leftSide); else len = elektraStrLen (leftSide); if (elektraRealloc ((void **) &lookupName, len) < 0) { ELEKTRA_SET_ERROR (87, parentKey, "Out of memory"); result = ERROR; goto Cleanup; } if (leftSide[0] == '@') snprintf (lookupName, len, "%s/%s", keyName (parentKey), leftSide + 1); else if (leftSide[0] == '.') // either . or .., doesn't matter here snprintf (lookupName, len, "%s/%s", keyName (curKey), leftSide); else snprintf (lookupName, len, "%s", leftSide); key = ksLookupByName (ks, lookupName, 0); if (cmpOp == NEX) { if (key) result = FALSE; else result = TRUE; goto Cleanup; } if (!key && cmpOp != OR && cmpOp != AND) { if (!keyGetMeta (parentKey, "error")) { ELEKTRA_SET_ERRORF (133, parentKey, "Key %s not found but is required for the evaluation of %s", lookupName, condition); } result = FALSE; goto Cleanup; } long ret; if (cmpOp == OR || cmpOp == AND) ret = compareStrings (leftSide, rightSide, NULL); else ret = compareStrings (keyString (key), compareTo, suffixList); switch (cmpOp) { case EQU: if (!ret) result = TRUE; break; case NOT: if (ret) result = TRUE; break; case LT: if (ret < 0) result = TRUE; break; case LE: if (ret <= 0) result = TRUE; break; case GT: if (ret > 0) result = TRUE; break; case GE: if (ret >= 0) result = TRUE; break; case SET: keySetString (key, compareTo); result = TRUE; break; case AND: if (ret == 0 && !strcmp (leftSide, "'1'")) result = TRUE; break; case OR: if (!strcmp (leftSide, "'1'") || (rightSide && !strcmp (rightSide, "'1'"))) result = TRUE; break; default: result = ERROR; break; } // freeing allocated heap Cleanup: if (lookupName) elektraFree (lookupName); if (compareTo) elektraFree (compareTo); return result; }
static void test_endings() { printf ("Test endings trie\n"); for (int i=0; i<4; ++i) { Trie *trie = 0; switch (i) { case 0: trie = test_insert (trie, "user/endings/","slash"); trie = test_insert (trie, "user/endings#","hash"); trie = test_insert (trie, "user/endings ","space"); trie = test_insert (trie, "user/endings\200","endings"); break; case 1: trie = test_insert (trie, "user/endings#","hash"); trie = test_insert (trie, "user/endings ","space"); trie = test_insert (trie, "user/endings\200","endings"); trie = test_insert (trie, "user/endings/","slash"); break; case 2: trie = test_insert (trie, "user/endings ","space"); trie = test_insert (trie, "user/endings\200","endings"); trie = test_insert (trie, "user/endings/","slash"); trie = test_insert (trie, "user/endings#","hash"); break; case 3: trie = test_insert (trie, "user/endings\200","endings"); trie = test_insert (trie, "user/endings ","space"); trie = test_insert (trie, "user/endings#","hash"); trie = test_insert (trie, "user/endings/","slash"); break; } exit_if_fail (trie, "trie was not build up successfully"); Key *searchKey = keyNew("user", KEY_END); Backend *backend = elektraTrieLookup(trie, searchKey); succeed_if (!backend, "there should be no backend"); Key *mp = keyNew("user/endings", KEY_VALUE, "slash", KEY_END); keySetName(searchKey, "user/endings"); backend = elektraTrieLookup(trie, searchKey); succeed_if (backend, "there should be a backend"); compare_key(backend->mountpoint, mp); keySetName(searchKey, "user/endings#"); keySetName(mp, "user/endings#"); keySetString(mp, "hash"); Backend *b2 = elektraTrieLookup(trie, searchKey); succeed_if (b2, "there should be a backend"); succeed_if (backend != b2, "should be other backend"); compare_key(b2->mountpoint, mp); keySetName(searchKey, "user/endings/_"); keySetName(mp, "user/endings"); keySetString(mp, "slash"); b2 = elektraTrieLookup(trie, searchKey); succeed_if (b2, "there should be a backend"); succeed_if (backend == b2, "should be the same backend"); compare_key(b2->mountpoint, mp); keySetName(searchKey, "user/endings/X"); keySetName(mp, "user/endings"); keySetString(mp, "slash"); b2 = elektraTrieLookup(trie, searchKey); succeed_if (b2, "there should be a backend"); succeed_if (backend == b2, "should be the same backend"); compare_key(b2->mountpoint, mp); keySetName(searchKey, "user/endings_"); b2 = elektraTrieLookup(trie, searchKey); succeed_if (!b2, "there should be no backend"); keySetName(searchKey, "user/endingsX"); b2 = elektraTrieLookup(trie, searchKey); succeed_if (!b2, "there should be no backend"); keySetName(searchKey, "user/endings!"); b2 = elektraTrieLookup(trie, searchKey); succeed_if (!b2, "there should be no backend"); keySetName(searchKey, "user/endings "); keySetName(mp, "user/endings "); keySetString(mp, "space"); b2 = elektraTrieLookup(trie, searchKey); succeed_if (b2, "there should be a backend"); succeed_if (backend != b2, "should be other backend"); compare_key(b2->mountpoint, mp); keySetName(searchKey, "user/endings\200"); keySetName(mp, "user/endings\200"); keySetString(mp, "endings"); b2 = elektraTrieLookup(trie, searchKey); succeed_if (b2, "there should be a backend"); succeed_if (backend != b2, "should be other backend"); compare_key(b2->mountpoint, mp); // output_trie(trie); elektraTrieClose(trie, 0); keyDel (mp); keyDel (searchKey); } }
/** Call a plugin's function in a child process * * This will wrap all the required information to execute the given * command in a keyset and send it over to the child process. Then * it waits for the child process's answer and copies the result * back into the original plugin keyset and plugin key. * * Typically called like * @code int elektraPluginSet (Plugin * handle, KeySet * returned, Key * parentKey) { ElektraPluginProcess * pp = elektraPluginGetData (handle); if (elektraPluginProcessIsParent (pp)) return elektraPluginProcessSend (pp, ELEKTRA_PLUGINPROCESS_SET, returned, parentKey); // actual plugin functionality to be executed in a child process return ELEKTRA_PLUGIN_STATUS_SUCCESS; } * @endcode * * @param pp the data structure containing the plugin's process information * @param command the plugin command that should be executed, e.g. ELEKTRA_PLUGINPROCESS_GET * @param originalKeySet the original key set that the parent process receives * @param key the original key the parent process receives * @retval ELEKTRA_PLUGIN_STATUS_ERROR if the child process communication failed * @retval the called plugin's return value otherwise * @see elektraPluginProcessIsParent for checking if we are in the parent or child process * @ingroup processplugin **/ int elektraPluginProcessSend (const ElektraPluginProcess * pp, pluginprocess_t command, KeySet * originalKeySet, Key * key) { // Ensure we have a keyset when trying to call GET SET and ERROR if ((command == ELEKTRA_PLUGINPROCESS_GET || command == ELEKTRA_PLUGINPROCESS_SET || command == ELEKTRA_PLUGINPROCESS_ERROR) && originalKeySet == NULL) { ELEKTRA_SET_ERROR (191, key, "originalKeySet has to exist when calling GET SET and ERROR via pluginprocess; but it is NULL"); return ELEKTRA_PLUGIN_STATUS_ERROR; } // Construct the command set that controls the pluginprocess communication KeySet * commandKeySet = ksNew (6, KS_END); ksAppendKey (commandKeySet, keyNew ("/pluginprocess/parent/name", KEY_VALUE, keyName (key), KEY_END)); Key * parentKey = keyDup (key); keySetName (parentKey, "/pluginprocess/parent"); ksAppendKey (commandKeySet, parentKey); char * commandStr = longToStr (command); ksAppendKey (commandKeySet, keyNew ("/pluginprocess/command", KEY_VALUE, commandStr, KEY_END)); elektraFree (commandStr); ksAppendKey (commandKeySet, keyNew ("/pluginprocess/version", KEY_VALUE, "1", KEY_END)); // Some plugin functions don't use keysets, in that case don't send any actual payload, signal via flag KeySet * keySet = originalKeySet != NULL ? ksDup (originalKeySet) : NULL; char * payloadSizeStr = longToStr (ksGetSize (originalKeySet)); ksAppendKey (commandKeySet, keyNew ("/pluginprocess/payload/size", KEY_VALUE, originalKeySet == NULL ? "-1" : payloadSizeStr, KEY_END)); elektraFree (payloadSizeStr); // Serialize, currently statically use dump as our default format, this already writes everything out to the pipe ELEKTRA_LOG ("Parent: Sending data to issue command %u it through pipe %s", command, keyString (pp->parentCommandPipeKey)); elektraInvoke2Args (pp->dump, "set", commandKeySet, pp->parentCommandPipeKey); if (keySet != NULL) { ELEKTRA_LOG ("Parent: Sending the payload keyset with %zd keys through the pipe %s", ksGetSize (keySet), keyString (pp->parentPayloadPipeKey)); elektraInvoke2Args (pp->dump, "set", keySet, pp->parentPayloadPipeKey); } // Deserialize ELEKTRA_LOG_DEBUG ("Parent: Waiting for the result now on pipe %s", keyString (pp->childCommandPipeKey)); elektraInvoke2Args (pp->dump, "get", commandKeySet, pp->childCommandPipeKey); if (keySet != NULL) { // clear the keyset before to avoid memleaks caused by dump char * endPtr; int prevErrno = errno; errno = 0; long payloadSize = strtol (keyString (ksLookupByName (commandKeySet, "/pluginprocess/payload/size", KDB_O_NONE)), &endPtr, 10); // in case the payload size fails to be transferred, that it shouldn't, we simply assume the previous size if (*endPtr != '\0' || errno == ERANGE || payloadSize < 0) payloadSize = ksGetSize (keySet); errno = prevErrno; ksDel (keySet); keySet = ksNew (payloadSize, KS_END); elektraInvoke2Args (pp->dump, "get", keySet, pp->childPayloadPipeKey); ELEKTRA_LOG ("Parent: We received %zd keys in return", ksGetSize (keySet)); } // Bring everything back in order by removing our process-related keys Key * parentDeserializedKey = ksLookupByName (commandKeySet, "/pluginprocess/parent", KDB_O_NONE); Key * resultKey = ksLookupByName (commandKeySet, "/pluginprocess/result", KDB_O_NONE); // Parse the result value char * endPtr; int prevErrno = errno; errno = 0; long lresult = strtol (keyString (resultKey), &endPtr, 10); if (*endPtr != '\0' || errno == ERANGE || lresult > INT_MAX || lresult < INT_MIN) { ELEKTRA_SET_ERRORF (191, key, "Received invalid return code or no KeySet: %s", keyString (resultKey)); lresult = ELEKTRA_PLUGIN_STATUS_ERROR; } else // Copy everything back into the actual keysets { Key * parentKeyInOriginalKeySet = keySet != NULL ? ksLookup (originalKeySet, key, KDB_O_NONE) : NULL; // maybe there are just 2 keys with the same name, can happen in theory, so compare memory int parentKeyExistsInOriginalKeySet = parentKeyInOriginalKeySet == key; // if the child added the parent key to the keyset pop it from the keyset // then reinsert key after we copied the data and delete this serialized copy Key * parentKeyInKeySet = keySet != NULL ? ksLookup (keySet, key, KDB_O_POP) : NULL; int childAddedParentKey = parentKeyInKeySet != NULL; // Unfortunately we can't use keyCopy here as ksAppendKey locks it so it will fail // This is the case if the parent key is also contained in the originalKeySet / has been appended // As an invariant we assume plugins don't change the parent key's name during a plugin call // This would interfere with keyset memberships keySetString (key, keyString (parentDeserializedKey)); // Clear metadata before, we allow children to modify it keyRewindMeta (key); const Key * currentMeta; while ((currentMeta = keyNextMeta (key)) != NULL) { keySetMeta (key, keyName (currentMeta), 0); } keyCopyAllMeta (key, parentDeserializedKey); if (childAddedParentKey) keyCopyAllMeta (key, parentKeyInKeySet); if (keySet != NULL) { // in case originalKeySet contains key this would make it stuck // thus remove it here and re-add it afterwards if (parentKeyExistsInOriginalKeySet) ksLookup (originalKeySet, parentKeyInOriginalKeySet, KDB_O_POP); ksCopy (originalKeySet, keySet); if (parentKeyExistsInOriginalKeySet || childAddedParentKey) ksAppendKey (originalKeySet, key); if (childAddedParentKey) keyDel (parentKeyInKeySet); } } errno = prevErrno; // Command finished, cleanup the remaining memory now ksDel (commandKeySet); if (keySet != NULL) ksDel (keySet); return lresult; // Safe, we had a bound check before, and plugins should return values in the int range }
/** Start the child process' command loop * * This will make the child process wait for plugin commands * and execute them, returning the result to the parent. This * is typically called in a plugin's open function. * * @param handle the plugin's handle * @param pp the data structure containing the plugin's process information * @see elektraPluginProcessInit how to use this function in a plugin * @ingroup processplugin **/ void elektraPluginProcessStart (Plugin * handle, ElektraPluginProcess * pp) { int counter = 0; do { KeySet * commandKeySet = ksNew (6, KS_END); KeySet * keySet = NULL; ELEKTRA_LOG_DEBUG ("Child: Wait for commands on pipe %s", keyString (pp->parentCommandPipeKey)); elektraInvoke2Args (pp->dump, "get", commandKeySet, pp->parentCommandPipeKey); if (ksGetSize (commandKeySet) == 0) { ELEKTRA_LOG_DEBUG ("Child: Failed to read from parentCommandPipe, exiting"); ksDel (commandKeySet); break; } Key * payloadSizeKey = ksLookupByName (commandKeySet, "/pluginprocess/payload/size", KDB_O_NONE); char * endPtr; // We'll always write some int value into it, so this should be fine int prevErrno = errno; errno = 0; long payloadSize = strtol (keyString (payloadSizeKey), &endPtr, 10); // in case the payload size fails to be transferred, that it shouldn't, we can only assume no payload if (*endPtr == '\0' && errno != ERANGE && payloadSize >= 0) { keySet = ksNew (payloadSize, KS_END); elektraInvoke2Args (pp->dump, "get", keySet, pp->parentPayloadPipeKey); ELEKTRA_LOG_DEBUG ("Child: We received a KeySet with %zd keys in it", ksGetSize (keySet)); } errno = prevErrno; Key * commandKey = ksLookupByName (commandKeySet, "/pluginprocess/command", KDB_O_NONE); Key * parentNameKey = ksLookupByName (commandKeySet, "/pluginprocess/parent/name", KDB_O_NONE); Key * parentKey = ksLookupByName (commandKeySet, "/pluginprocess/parent", KDB_O_POP); Key * key = keyDup (parentKey); keySetName (key, keyString (parentNameKey)); int result = ELEKTRA_PLUGIN_STATUS_ERROR; // We'll always write some int value into it, so this should be fine prevErrno = errno; errno = 0; long command = strtol (keyString (commandKey), &endPtr, 10); if (*endPtr == '\0' && errno != ERANGE) { ELEKTRA_LOG ("Child: We want to execute the command with the value %ld now", command); // Its hard to figure out the enum size in a portable way but for this comparison it should be ok switch (command) { case ELEKTRA_PLUGINPROCESS_OPEN: counter++; result = handle->kdbOpen (handle, key); break; case ELEKTRA_PLUGINPROCESS_CLOSE: counter--; result = handle->kdbClose (handle, key); break; case ELEKTRA_PLUGINPROCESS_GET: result = handle->kdbGet (handle, keySet, key); break; case ELEKTRA_PLUGINPROCESS_SET: result = handle->kdbSet (handle, keySet, key); break; case ELEKTRA_PLUGINPROCESS_ERROR: result = handle->kdbError (handle, keySet, key); break; default: result = ELEKTRA_PLUGIN_STATUS_ERROR; } ELEKTRA_LOG_DEBUG ("Child: Command executed with return value %d", result); } else { ELEKTRA_LOG_DEBUG ("Child: Unrecognized command %s", keyString (commandKey)); ELEKTRA_SET_ERRORF (191, key, "Received invalid command code or no KeySet: %s", keyString (commandKey)); } errno = prevErrno; char * resultStr = longToStr (result); ksAppendKey (commandKeySet, keyNew ("/pluginprocess/result", KEY_VALUE, resultStr, KEY_END)); elektraFree (resultStr); keySetName (key, "/pluginprocess/parent"); ksAppendKey (commandKeySet, key); keyDel (parentKey); ELEKTRA_LOG_DEBUG ("Child: Writing the results back to the parent"); elektraInvoke2Args (pp->dump, "set", commandKeySet, pp->childCommandPipeKey); if (keySet != NULL) { char * resultPayloadSize = longToStr (ksGetSize (keySet)); keySetString (payloadSizeKey, resultPayloadSize); elektraFree (resultPayloadSize); elektraInvoke2Args (pp->dump, "set", keySet, pp->childPayloadPipeKey); ksDel (keySet); } ksDel (commandKeySet); ELEKTRA_LOG ("Child: Command handled, startup counter is at %d", counter); } while (counter); // Final Cleanup ELEKTRA_LOG_DEBUG ("Child: All done, exiting the child process now"); cleanupPluginData (pp, 0, 1); // All done, exit the child process so it won't do any actual effects in elektra _Exit (EXIT_SUCCESS); }
static KeySet * convertKeys (Key ** keyArray, size_t numKeys, KeySet * orig) { Key * current = 0; Key * prevAppendTarget = 0; KeySet * prevConverted = ksNew (0, KS_END); KeySet * nextConverted = ksNew (0, KS_END); KeySet * result = ksNew (0, KS_END); for (size_t index = 0; index < numKeys; index++) { current = keyArray[index]; if (!keyGetMeta (current, CONVERT_METANAME)) { /* flush out "previous" and "next" keys which may have been collected * because the current key serves as a new border */ ksAppend (result, prevConverted); flushConvertedKeys (prevAppendTarget, prevConverted, orig); prevAppendTarget = current; ksAppend (result, nextConverted); flushConvertedKeys (current, nextConverted, orig); continue; } const char * appendMode = getAppendMode (current); const char * metaName = keyString (keyGetMeta (current, CONVERT_METANAME)); Key * bufferKey = 0; if (!strcmp (appendMode, "previous")) { ksAppendKey (prevConverted, current); } if (!strcmp (appendMode, "next")) { ksAppendKey (nextConverted, current); } if (!strcmp (appendMode, "parent")) { Key * parent = findNearestParent (current, orig); elektraKeyAppendMetaLine (parent, metaName, keyString (current)); ksAppendKey (result, current); removeKeyFromResult (current, parent, orig); } if (bufferKey) { keySetString (bufferKey, keyName (current)); } } ksAppend (result, prevConverted); flushConvertedKeys (prevAppendTarget, prevConverted, orig); ksAppend (result, nextConverted); flushConvertedKeys (0, nextConverted, orig); ksDel (nextConverted); ksDel (prevConverted); return result; }
static void test_default() { printf ("Test mounting with default\n"); KDB *kdb = kdb_new(); Key *errorKey = keyNew(0); KeySet *modules = modules_config(); succeed_if (elektraMountOpen(kdb, root_config(), modules, errorKey) == 0, "could not buildup mount"); succeed_if (elektraMountDefault(kdb, modules, errorKey) == 0, "could not mount default backend"); succeed_if (kdb->split->size == 6, "size of split not correct"); Key *mp = keyNew("spec", KEY_VALUE, "root", KEY_END); compare_key(mp, kdb->split->parents[0]); keySetName(mp, "dir"); keySetString (mp, "root"); compare_key(mp, kdb->split->parents[1]); keySetName(mp, "user"); keySetString (mp, "root"); compare_key(mp, kdb->split->parents[2]); keySetName(mp, "system"); keySetString (mp, "root"); compare_key(mp, kdb->split->parents[3]); keySetName(mp, "system/elektra"); keySetString (mp, "default"); compare_key(mp, kdb->split->parents[5]); // must be last, needed later keySetName(mp, "user/tests/simple"); keySetString (mp, "simple"); compare_key(mp, kdb->split->parents[4]); succeed_if(output_warnings (errorKey), "warnings found"); succeed_if(output_error (errorKey), "error found"); exit_if_fail (kdb->trie, "trie was not build up successfully"); // output_trie (kdb->trie); Key *searchKey = keyNew("", KEY_END); Key *rmp = keyNew("", KEY_VALUE, "root", KEY_END); elektraKeySetName(rmp, "/", KEY_CASCADING_NAME); Backend *b2 = 0; keySetName (searchKey, "user"); b2 = elektraTrieLookup(kdb->trie, searchKey); succeed_if (b2, "there should be a backend"); compare_key(b2->mountpoint, rmp); Backend *backend = 0; keySetName(searchKey, "user/tests/simple"); backend = elektraTrieLookup(kdb->trie, searchKey); succeed_if (backend, "there should be a backend"); compare_key(backend->mountpoint, mp); keySetName(searchKey, "user/tests/simple/below"); b2 = elektraTrieLookup(kdb->trie, searchKey); succeed_if (b2, "there should be a backend"); succeed_if (backend == b2, "should be same backend"); compare_key(b2->mountpoint, mp); keySetName(searchKey, "user/tests/simple/deep/below"); b2 = elektraTrieLookup(kdb->trie, searchKey); succeed_if (b2, "there should be a backend"); succeed_if (backend == b2, "should be same backend"); compare_key(b2->mountpoint, mp); Key *dmp = keyNew ("", KEY_VALUE, "default", KEY_END); keySetName(searchKey, "system/elektra"); b2 = elektraTrieLookup(kdb->trie, searchKey); succeed_if (b2, "there should be a backend"); succeed_if (b2 == kdb->defaultBackend, "should be the default backend"); compare_key(b2->mountpoint, dmp); keySetName(searchKey, "system/elektra/below"); b2 = elektraTrieLookup(kdb->trie, searchKey); succeed_if (b2, "there should be a backend"); succeed_if (b2 == kdb->defaultBackend, "should be the default backend"); compare_key(b2->mountpoint, dmp); keyDel (dmp); keyDel (mp); keyDel (rmp); keyDel (searchKey); kdb_del (kdb); keyDel (errorKey); ksDel (modules); }
static void test_modules() { printf ("Test mounting with modules\n"); KDB *kdb = kdb_new(); Key *errorKey = keyNew(0); KeySet *modules = modules_config(); succeed_if (elektraMountOpen(kdb, root_config(), modules, errorKey) == 0, "could not buildup mount"); succeed_if (elektraMountDefault(kdb, modules, errorKey) == 0, "could not mount default backend"); succeed_if (elektraMountModules(kdb, modules, errorKey) == 0, "could not mount modules"); succeed_if(output_warnings (errorKey), "warnings found"); succeed_if(output_error (errorKey), "error found"); succeed_if (kdb->split->size == 8, "size of split not correct"); Key *mp = keyNew("spec", KEY_VALUE, "root", KEY_END); compare_key(mp, kdb->split->parents[0]); keySetName(mp, "dir"); keySetString (mp, "root"); compare_key(mp, kdb->split->parents[1]); keySetName(mp, "user"); keySetString (mp, "root"); compare_key(mp, kdb->split->parents[2]); keySetName(mp, "system"); keySetString (mp, "root"); compare_key(mp, kdb->split->parents[3]); /* we cannot exactly know where resolver+dump is located *(depending on alphabet) keySetName(mp, "system/elektra/modules/"KDB_DEFAULT_RESOLVER); keySetString (mp, "modules"); compare_key(mp, kdb->split->parents[4]); */ keySetName(mp, "system/elektra"); keySetString (mp, "default"); compare_key(mp, kdb->split->parents[5]); keySetName(mp, "user/tests/simple"); keySetString (mp, "simple"); compare_key(mp, kdb->split->parents[4]); exit_if_fail (kdb->trie, "trie was not build up successfully"); // output_trie (kdb->trie); Key *searchKey = keyNew("", KEY_END); Key *rmp = keyNew("", KEY_VALUE, "root", KEY_END); elektraKeySetName(rmp, "/", KEY_CASCADING_NAME); Backend *b2 = 0; keySetName (searchKey, "user"); b2 = elektraTrieLookup(kdb->trie, searchKey); succeed_if (b2, "there should be a backend"); compare_key(b2->mountpoint, rmp); Backend *backend = 0; keySetName(searchKey, "user/tests/simple"); backend = elektraTrieLookup(kdb->trie, searchKey); succeed_if (backend, "there should be a backend"); compare_key(backend->mountpoint, mp); keySetName(searchKey, "user/tests/simple/below"); b2 = elektraTrieLookup(kdb->trie, searchKey); succeed_if (b2, "there should be a backend"); succeed_if (backend == b2, "should be same backend"); compare_key(b2->mountpoint, mp); keySetName(searchKey, "user/tests/simple/deep/below"); b2 = elektraTrieLookup(kdb->trie, searchKey); succeed_if (b2, "there should be a backend"); succeed_if (backend == b2, "should be same backend"); compare_key(b2->mountpoint, mp); Key *dmp = keyNew ("", KEY_VALUE, "default", KEY_END); keySetName(searchKey, "system/elektra"); b2 = elektraTrieLookup(kdb->trie, searchKey); succeed_if (b2, "there should be a backend"); succeed_if (b2 == kdb->defaultBackend, "should be the default backend"); compare_key(b2->mountpoint, dmp); keySetName(searchKey, "system/elektra/below"); b2 = elektraTrieLookup(kdb->trie, searchKey); succeed_if (b2, "there should be a backend"); succeed_if (b2 == kdb->defaultBackend, "should be the default backend"); compare_key(b2->mountpoint, dmp); Key *mmp = keyNew ("system/elektra/modules", KEY_VALUE, "modules", KEY_END); keyAddBaseName (mmp, "default"); /* keySetName(searchKey, "system/elektra/modules/default"); b2 = elektraTrieLookup(kdb->trie, searchKey); succeed_if (b2, "there should be a backend"); succeed_if (b2 != kdb->defaultBackend, "should not be the default backend"); compare_key(b2->mountpoint, mmp); */ keyDel (mmp); keyDel (dmp); keyDel (mp); keyDel (rmp); keyDel (searchKey); kdb_del (kdb); keyDel (errorKey); ksDel (modules); }
/** * @brief decrypt the file specified at parentKey * @param pluginConfig holds the plugin configuration * @param parentKey holds the path to the file to be encrypted. Will hold an error description in case of failure. * @param state holds the plugin state * @retval 1 on success * @retval -1 on error, errorKey holds an error description */ static int fcryptDecrypt (KeySet * pluginConfig, Key * parentKey, fcryptState * state) { int tmpFileFd = -1; char * tmpFile = getTemporaryFileName (pluginConfig, keyString (parentKey), &tmpFileFd); if (!tmpFile) { ELEKTRA_SET_ERROR (87, parentKey, "Memory allocation failed"); return -1; } const size_t testMode = inTestMode (pluginConfig); // prepare argument vector for gpg call // 8 static arguments (magic number below) are: // 1. path to the binary // 2. --batch // 3. -o // 4. path to tmp file // 5. yes // 6. -d // 7. file to be encrypted // 8. NULL terminator int argc = 8 + (2 * testMode); char * argv[argc]; int i = 0; argv[i++] = NULL; argv[i++] = "--batch"; argv[i++] = "--yes"; // if we are in test mode we add the trust model if (testMode) { argv[i++] = "--trust-model"; argv[i++] = "always"; } argv[i++] = "-o"; argv[i++] = tmpFile; argv[i++] = "-d"; // safely discarding const from keyString() return value argv[i++] = (char *) keyString (parentKey); argv[i++] = NULL; // NOTE the decryption process works like this: // gpg2 --batch --yes -o tmpfile -d configFile int result = ELEKTRA_PLUGIN_FUNCTION (gpgCall) (pluginConfig, parentKey, NULL, argv, argc); if (result == 1) { state->originalFilePath = elektraStrDup (keyString (parentKey)); state->tmpFilePath = tmpFile; state->tmpFileFd = tmpFileFd; keySetString (parentKey, tmpFile); } else { // if anything went wrong above the temporary file is shredded and removed shredTemporaryFile (tmpFileFd, parentKey); if (unlink (tmpFile)) { ELEKTRA_ADD_WARNINGF (ELEKTRA_WARNING_FCRYPT_UNLINK, parentKey, "Affected file: %s, error description: %s", tmpFile, strerror (errno)); } if (close (tmpFileFd)) { ELEKTRA_ADD_WARNINGF (ELEKTRA_WARNING_FCRYPT_CLOSE, parentKey, "%s", strerror (errno)); } elektraFree (tmpFile); } return result; }
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 (ELEKTRA_ERROR_CRYPTO_DECRYPT_FAIL, 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 (ELEKTRA_ERROR_CRYPTO_DECRYPT_FAIL, 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 (ELEKTRA_ERROR_CRYPTO_DECRYPT_FAIL, 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 (ELEKTRA_ERROR_CRYPTO_DECRYPT_FAIL, 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; }