LCOV - code coverage report
Current view: top level - src/bindings/intercept/fs - intercept.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 0 213 0.0 %
Date: 2019-09-12 12:28:41 Functions: 0 12 0.0 %

          Line data    Source code
       1             : #define _GNU_SOURCE
       2             : #include <dlfcn.h>
       3             : #include <fcntl.h>
       4             : #include <kdb.h>
       5             : #include <libgen.h>
       6             : #include <limits.h>
       7             : #include <linux/limits.h>
       8             : #include <pwd.h>
       9             : #include <stdarg.h>
      10             : #include <stddef.h>
      11             : #include <stdio.h>
      12             : #include <stdlib.h>
      13             : #include <string.h>
      14             : #include <sys/time.h>
      15             : #include <sys/types.h>
      16             : #include <unistd.h>
      17             : 
      18             : #include <kdb.h>
      19             : #include <kdbmodule.h>
      20             : #include <kdbprivate.h>
      21             : 
      22             : #define PRELOAD_PATH "/elektra/intercept/open"
      23             : #define TV_MAX_DIGITS 26
      24             : #define RELEVANT_FRAME 1
      25             : 
      26             : struct _Node
      27             : {
      28             :         char * key;
      29             :         char * value;
      30             :         unsigned short oflags;
      31             :         char * exportType;
      32             :         char * exportKey;
      33             :         time_t creationTime;
      34             :         struct _Node * next;
      35             : };
      36             : typedef struct _Node Node;
      37             : static Node * head = NULL;
      38             : 
      39           0 : static void canonicalizePath (char * buffer, char * toAppend)
      40             : {
      41           0 :         char * destPtr = buffer + strlen (buffer);
      42           0 :         for (unsigned int i = 0; i < strlen (toAppend); ++i)
      43             :         {
      44           0 :                 if (!strncmp ((toAppend + i), "../", 3))
      45             :                 {
      46           0 :                         i += 2;
      47           0 :                         const char * dir = dirname (buffer);
      48           0 :                         size_t dirLen = strlen (dir);
      49           0 :                         destPtr = buffer + dirLen;
      50           0 :                         if (strcmp (dir, "/")) *destPtr++ = '/';
      51           0 :                         *destPtr = '\0';
      52           0 :                         continue;
      53             :                 }
      54           0 :                 else if (!strncmp ((toAppend + i), "./", 2))
      55             :                 {
      56           0 :                         ++i;
      57           0 :                         continue;
      58             :                 }
      59           0 :                 else if (!strncmp ((toAppend + i), "//", 2))
      60             :                 {
      61           0 :                         continue;
      62             :                 }
      63             :                 else
      64             :                 {
      65           0 :                         *destPtr++ = toAppend[i];
      66             :                 }
      67             :         }
      68           0 : }
      69             : 
      70           0 : static char * createAbsolutePath (const char * path, const char * cwd)
      71             : {
      72           0 :         if (path[0] == '/')
      73           0 :                 return elektraStrDup (path);
      74             :         else
      75             :         {
      76           0 :                 char * absPath = NULL;
      77             :                 size_t pathlen;
      78           0 :                 char * pathPtr = NULL;
      79           0 :                 if (path[0] == '~')
      80             :                 {
      81           0 :                         struct passwd * pwd = getpwuid (getuid ());
      82           0 :                         pathlen = strlen (path) + strlen (pwd->pw_dir) + 2;
      83           0 :                         absPath = calloc (pathlen, sizeof (char));
      84           0 :                         snprintf (absPath, pathlen, "%s/", pwd->pw_dir);
      85           0 :                         pathPtr = (char *) (path + 2);
      86             :                 }
      87             :                 else
      88             :                 {
      89           0 :                         pathlen = strlen (path) + strlen (cwd) + 2;
      90           0 :                         absPath = calloc (pathlen, sizeof (char));
      91           0 :                         snprintf (absPath, pathlen, "%s/", cwd);
      92           0 :                         pathPtr = (char *) path;
      93             :                 }
      94           0 :                 canonicalizePath (absPath, pathPtr);
      95           0 :                 return absPath;
      96             :         }
      97             : }
      98             : 
      99           0 : static const char * genTemporaryFilename (void)
     100             : {
     101             :         struct timeval tv;
     102           0 :         gettimeofday (&tv, 0);
     103           0 :         const char * fileName = "/tmp/.elektra_generated";
     104           0 :         size_t len = strlen (fileName) + TV_MAX_DIGITS + 1;
     105           0 :         char * tmpFile = elektraCalloc (len);
     106           0 :         snprintf (tmpFile, len, "%s_%lu:%lu", fileName, tv.tv_sec, tv.tv_usec);
     107           0 :         return tmpFile;
     108             : }
     109             : 
     110             : static void init (void) __attribute__ ((constructor));
     111             : static void cleanup (void) __attribute__ ((destructor));
     112           0 : void init (void)
     113             : {
     114             :         char cwd[PATH_MAX];
     115           0 :         getcwd (cwd, PATH_MAX);
     116           0 :         KeySet * tmpKS = ksNew (0, KS_END);
     117           0 :         Key * parentKey = keyNew (PRELOAD_PATH, KEY_CASCADING_NAME, KEY_END);
     118             :         Key * key;
     119           0 :         KDB * handle = kdbOpen (parentKey);
     120           0 :         kdbGet (handle, tmpKS, parentKey);
     121           0 :         KeySet * ks = ksCut (tmpKS, parentKey);
     122           0 :         ksRewind (ks);
     123           0 :         ssize_t size = ksGetSize (ks);
     124           0 :         if (size <= 1) goto CleanUp;
     125           0 :         Node * current = head;
     126           0 :         ksNext (ks); // skip head
     127           0 :         while ((key = ksNext (ks)) != NULL)
     128             :         {
     129           0 :                 if (!keyIsDirectBelow (parentKey, key)) continue;
     130           0 :                 Node * tmp = calloc (1, sizeof (Node));
     131           0 :                 tmp->key = createAbsolutePath (keyBaseName (key), cwd);
     132           0 :                 if (!strcmp (keyString (key), ""))
     133           0 :                         tmp->value = NULL;
     134             :                 else
     135           0 :                         tmp->value = createAbsolutePath (keyString (key), cwd);
     136           0 :                 tmp->oflags = (unsigned short) -1;
     137           0 :                 Key * lookupKey = keyDup (key);
     138           0 :                 keyAddBaseName (lookupKey, "readonly");
     139           0 :                 Key * found = ksLookup (ks, lookupKey, 0);
     140           0 :                 if (found)
     141             :                 {
     142           0 :                         if (!strcmp (keyString (found), "1"))
     143             :                         {
     144           0 :                                 tmp->oflags = O_RDONLY;
     145             :                         }
     146             :                 }
     147           0 :                 keySetBaseName (lookupKey, 0);
     148           0 :                 keyAddBaseName (lookupKey, "generate");
     149           0 :                 found = ksLookup (ks, lookupKey, 0);
     150           0 :                 if (found)
     151             :                 {
     152           0 :                         if (tmp->value == NULL) tmp->value = (char *) genTemporaryFilename ();
     153           0 :                         tmp->exportKey = elektraStrDup (keyString (found));
     154           0 :                         keyAddBaseName (lookupKey, "plugin");
     155           0 :                         found = ksLookup (ks, lookupKey, 0);
     156           0 :                         if (found)
     157             :                         {
     158           0 :                                 tmp->exportType = elektraStrDup (keyString (found));
     159             :                         }
     160             :                         else
     161             :                         {
     162           0 :                                 tmp->exportKey = NULL;
     163           0 :                                 tmp->exportType = NULL;
     164             :                         }
     165             :                 }
     166             :                 else
     167             :                 {
     168           0 :                         tmp->exportKey = NULL;
     169           0 :                         tmp->exportType = NULL;
     170             :                 }
     171           0 :                 keyDel (lookupKey);
     172           0 :                 if (tmp->value == NULL) tmp->value = createAbsolutePath (keyBaseName (key), cwd);
     173           0 :                 tmp->creationTime = 0;
     174           0 :                 tmp->next = NULL;
     175           0 :                 if (current == NULL)
     176             :                 {
     177           0 :                         head = tmp;
     178           0 :                         current = head;
     179             :                 }
     180             :                 else
     181             :                 {
     182           0 :                         current->next = tmp;
     183           0 :                         current = current->next;
     184             :                 }
     185             :         }
     186             : CleanUp:
     187           0 :         ksAppend (tmpKS, ks);
     188           0 :         ksDel (tmpKS);
     189           0 :         ksDel (ks);
     190           0 :         kdbClose (handle, parentKey);
     191           0 :         keyDel (parentKey);
     192           0 : }
     193             : 
     194             : 
     195           0 : void cleanup (void)
     196             : {
     197           0 :         Node * current = head;
     198           0 :         while (current)
     199             :         {
     200           0 :                 Node * tmp = current;
     201           0 :                 free (current->key);
     202           0 :                 if (current->value) free (current->value);
     203           0 :                 if (current->exportKey)
     204             :                 {
     205           0 :                         free (current->exportKey);
     206           0 :                         free (current->exportType);
     207             :                 }
     208           0 :                 current = current->next;
     209           0 :                 free (tmp);
     210             :         }
     211           0 : }
     212             : 
     213           0 : static Node * resolvePathname (const char * pathname)
     214             : {
     215           0 :         Node * node = NULL;
     216           0 :         if (pathname)
     217             :         {
     218             :                 char cwd[PATH_MAX];
     219           0 :                 getcwd (cwd, PATH_MAX);
     220           0 :                 char * resolvedPath = NULL;
     221           0 :                 if (pathname[0] != '/')
     222             :                 {
     223           0 :                         resolvedPath = createAbsolutePath (pathname, cwd);
     224             :                 }
     225             :                 else
     226             :                 {
     227           0 :                         resolvedPath = calloc (strlen (pathname) + 1, sizeof (char));
     228           0 :                         size_t size = sizeof (resolvedPath);
     229           0 :                         memset (resolvedPath, 0, size);
     230           0 :                         canonicalizePath (resolvedPath, (char *) pathname);
     231             :                 }
     232           0 :                 Node * current = head;
     233           0 :                 while (current)
     234             :                 {
     235           0 :                         if (!strcmp (current->key, resolvedPath))
     236             :                         {
     237             :                                 node = current;
     238             :                                 break;
     239             :                         }
     240           0 :                         current = current->next;
     241             :                 }
     242           0 :                 free (resolvedPath);
     243             :         }
     244           0 :         return node;
     245             : }
     246             : 
     247             : int __xstat (int ver, const char * path, struct stat * buf);
     248             : int __xstat64 (int ver, const char * path, struct stat64 * buf);
     249             : 
     250           0 : static void exportConfiguration (Node * node)
     251             : {
     252           0 :         Key * key = keyNew (node->exportKey, KEY_END);
     253           0 :         KDB * handle = kdbOpen (key);
     254           0 :         KeySet * ks = ksNew (0, KS_END);
     255           0 :         kdbGet (handle, ks, key);
     256             :         KeySet * exportKS;
     257           0 :         exportKS = ksCut (ks, key);
     258           0 :         KeySet * modules = ksNew (0, KS_END);
     259           0 :         elektraModulesInit (modules, 0);
     260           0 :         KeySet * conf = ksNew (0, KS_END);
     261           0 :         Plugin * check = elektraPluginOpen (node->exportType, modules, conf, key);
     262           0 :         keySetString (key, node->value);
     263           0 :         ksRewind (exportKS);
     264           0 :         check->kdbSet (check, exportKS, key);
     265           0 :         ksDel (conf);
     266           0 :         ksAppend (ks, exportKS);
     267           0 :         ksDel (exportKS);
     268           0 :         elektraModulesClose (modules, 0);
     269           0 :         ksDel (modules);
     270           0 :         keyDel (key);
     271           0 :         ksDel (ks);
     272           0 :         kdbClose (handle, 0);
     273             :         struct stat buf;
     274           0 :         if (!__xstat (3, node->value, &buf)) node->creationTime = buf.st_mtim.tv_sec;
     275           0 : }
     276             : 
     277             : 
     278             : // e.g. we intercept successive calls of stat and open
     279             : static inline int createdWithinTimeframe (int (*f) (int, const char *, struct stat *), Node * node, int frame)
     280             : {
     281             :         struct stat buf;
     282           0 :         if (!f (3, node->value, &buf))
     283             :         {
     284           0 :                 if (node->creationTime && ((node->creationTime + frame) < buf.st_mtim.tv_sec)) return 0;
     285             :         }
     286             :         else
     287             :         {
     288             :                 return 0;
     289             :         }
     290             :         return 1;
     291             : }
     292             : 
     293             : typedef int (*orig_open_f_type) (const char * pathname, int flags, ...);
     294             : 
     295             : typedef union
     296             : {
     297             :         void * d;
     298             :         orig_open_f_type f;
     299             : } OpenSymbol;
     300             : 
     301             : 
     302             : int open (const char * pathname, int flags, ...)
     303             : {
     304           0 :         Node * node = resolvePathname (pathname);
     305           0 :         const char * newPath = NULL;
     306           0 :         unsigned short newFlags = (unsigned short) -1;
     307           0 :         if (!node)
     308             :         {
     309             :                 newPath = pathname;
     310             :         }
     311             :         else
     312             :         {
     313           0 :                 if (!(node->exportType))
     314             :                 {
     315           0 :                         newPath = node->value;
     316           0 :                         newFlags = node->oflags;
     317             :                 }
     318             :                 else
     319             :                 {
     320           0 :                         newPath = node->value;
     321           0 :                         if (!createdWithinTimeframe (__xstat, node, RELEVANT_FRAME)) exportConfiguration (node);
     322             :                 }
     323             :         }
     324           0 :         if (newFlags == O_RDONLY)
     325             :         {
     326           0 :                 flags = (flags & (~(0 | O_WRONLY | O_APPEND)));
     327             :         }
     328             :         OpenSymbol orig_open;
     329           0 :         orig_open.d = dlsym (RTLD_NEXT, "open");
     330             : 
     331             :         int fd;
     332           0 :         if (flags & O_CREAT)
     333             :         {
     334             :                 int mode;
     335             :                 va_list argptr;
     336           0 :                 va_start (argptr, flags);
     337           0 :                 mode = va_arg (argptr, int);
     338           0 :                 va_end (argptr);
     339           0 :                 fd = orig_open.f (newPath, flags, mode);
     340             :         }
     341             :         else
     342             :         {
     343           0 :                 fd = orig_open.f (newPath, flags);
     344             :         }
     345           0 :         return fd;
     346             : }
     347             : int open64 (const char * pathname, int flags, ...)
     348             : {
     349           0 :         Node * node = resolvePathname (pathname);
     350           0 :         const char * newPath = NULL;
     351           0 :         unsigned short newFlags = (unsigned short) -1;
     352           0 :         if (!node)
     353             :         {
     354             :                 newPath = pathname;
     355             :         }
     356             :         else
     357             :         {
     358           0 :                 if (!(node->exportType))
     359             :                 {
     360           0 :                         newPath = node->value;
     361           0 :                         newFlags = node->oflags;
     362             :                 }
     363             :                 else
     364             :                 {
     365           0 :                         newPath = node->value;
     366           0 :                         if (!createdWithinTimeframe (__xstat, node, RELEVANT_FRAME)) exportConfiguration (node);
     367             :                 }
     368             :         }
     369           0 :         if (newFlags == O_RDONLY)
     370             :         {
     371           0 :                 flags = (flags & (~(0 | O_WRONLY | O_APPEND)));
     372             :         }
     373             : 
     374             :         OpenSymbol orig_open64;
     375           0 :         orig_open64.d = dlsym (RTLD_NEXT, "open64");
     376             : 
     377             :         int fd;
     378           0 :         if (flags & O_CREAT)
     379             :         {
     380             :                 int mode;
     381             :                 va_list argptr;
     382           0 :                 va_start (argptr, flags);
     383           0 :                 mode = va_arg (argptr, int);
     384           0 :                 va_end (argptr);
     385           0 :                 fd = orig_open64.f (newPath, flags, mode);
     386             :         }
     387             :         else
     388             :         {
     389           0 :                 fd = orig_open64.f (newPath, flags);
     390             :         }
     391           0 :         return fd;
     392             : }
     393             : 
     394             : typedef int (*orig_xstat_f_type) (int ver, const char * path, struct stat * buf);
     395             : typedef int (*orig_xstat64_f_type) (int ver, const char * path, struct stat64 * buf);
     396             : 
     397             : typedef union
     398             : {
     399             :         void * d;
     400             :         orig_xstat_f_type f;
     401             : } XstatSymbol;
     402             : 
     403             : typedef union
     404             : {
     405             :         void * d;
     406             :         orig_xstat64_f_type f;
     407             : } Xstat64Symbol;
     408             : 
     409           0 : int __xstat (int ver, const char * path, struct stat * buf)
     410             : {
     411           0 :         Node * node = resolvePathname (path);
     412           0 :         const char * newPath = NULL;
     413             :         XstatSymbol orig_xstat;
     414           0 :         orig_xstat.d = dlsym (RTLD_NEXT, "__xstat");
     415           0 :         if (!node)
     416             :                 newPath = path;
     417             :         else
     418             :         {
     419           0 :                 if (!(node->exportType))
     420             :                 {
     421           0 :                         newPath = node->value;
     422             :                 }
     423             :                 else
     424             :                 {
     425           0 :                         newPath = node->value;
     426           0 :                         if (!createdWithinTimeframe (orig_xstat.f, node, RELEVANT_FRAME)) exportConfiguration (node);
     427             :                 }
     428             :         }
     429             : 
     430           0 :         return orig_xstat.f (ver, newPath, buf);
     431             : }
     432             : 
     433           0 : int __xstat64 (int ver, const char * path, struct stat64 * buf)
     434             : {
     435           0 :         Node * node = resolvePathname (path);
     436           0 :         const char * newPath = NULL;
     437             :         Xstat64Symbol orig_xstat64;
     438           0 :         orig_xstat64.d = dlsym (RTLD_NEXT, "__xstat64");
     439           0 :         if (!node)
     440             :                 newPath = path;
     441             :         else
     442             :         {
     443           0 :                 if (!(node->exportType))
     444             :                 {
     445           0 :                         newPath = node->value;
     446             :                 }
     447             :                 else
     448             :                 {
     449           0 :                         newPath = node->value;
     450           0 :                         if (!createdWithinTimeframe (__xstat, node, RELEVANT_FRAME)) exportConfiguration (node);
     451             :                 }
     452             :         }
     453             : 
     454           0 :         return orig_xstat64.f (ver, newPath, buf);
     455             : }
     456             : 
     457             : typedef int (*orig_access_f_type) (const char * pathname, int mode);
     458             : 
     459             : typedef union
     460             : {
     461             :         void * d;
     462             :         orig_access_f_type f;
     463             : } AccessSymbol;
     464             : 
     465             : int access (const char * pathname, int mode)
     466             : {
     467           0 :         Node * node = resolvePathname (pathname);
     468           0 :         if (node && mode == F_OK) return 0;
     469             :         AccessSymbol orig_access;
     470           0 :         orig_access.d = dlsym (RTLD_NEXT, "access");
     471           0 :         return orig_access.f (pathname, mode);
     472             : }

Generated by: LCOV version 1.13