:: Re: [DNG] logging uses of machine-i…
Top Page
Delete this message
Reply to this message
Author: Didier Kryn
To: dng@lists.dyne.org
Subject: Re: [DNG] logging uses of machine-id
Le 11/03/2019 à 15:51, KatolaZ a écrit :
> On Mon, Mar 11, 2019 at 03:32:57PM +0100, Didier Kryn wrote:
>>     Please find in atttachment a quickly hacked C program which writes a
>> line on standard output everytime a process opens a given file.
>>     The invocation syntax to watch machine-id is 'fawatch
>> /var/lib/machine-id'
> Hi Didier,
> if you mean the dbus machine-id, then it's /var/lib/dbus/machine-id.

    Yes. And I found 2 bugs when running it in the background from
/etc/rc.local. Here's the corrected version.


#include <sys/types.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/fanotify.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <pwd.h>

ssize_t readproc(pid_t pid, const char *fname, char *buf, size_t len);

int main(int argc, char **argv)
  static char buf[4096];
  static char cmdline[80], loginuid[80];
  static char *progname;
  struct fanotify_event_metadata  *fh;
  struct fanotify_response response;
  int fafd;
  const unsigned faflags = FAN_CLASS_PRE_CONTENT | FAN_CLOEXEC;
  /* If we don't specify FAN_CLASS_PRE_CONTENT, and FAN_OPEN_PERM, a very short
     process  may be finished before we can read its command line and owner.
     With these flags, it'll be held until we've sent the permisssion. */

    /* set progname to point to basename(argv[0]) */
    int i;
    for( i=strlen(argv[0])-1;   argv[0][i] != '/';    i-- ) /* nop */;
    if( argv[0][i] == '/' ) i++;
    progname = argv[0] + i;

  fafd = fanotify_init(faflags, O_RDONLY | O_CLOEXEC);
  if( fafd < 0 )
      fprintf( stderr, "%s: error returned by fanotify_init(): %s\n",
           progname, strerror(errno) );
      return EXIT_FAILURE;

  if(  fanotify_mark(fafd, FAN_MARK_ADD, FAN_OPEN_PERM, AT_FDCWD, argv[1])  )
      if( errno == ENOENT )
    fprintf( stderr, "%s: %s: %s\n", progname, argv[1], strerror(errno) );
    fprintf( stderr, "%s: error returned by fanotify_mark(): %s\n",
           progname, strerror(errno) );
      return EXIT_FAILURE;

  /* loop on reading fanotify filedescriptor */
      size_t size;
      char *end, *c;
      size = read( fafd, buf, sizeof(buf) );
      if(size < 1)
      fprintf( stderr, "%s error reading fanotify filedescriptor: %s\n",
           progname, strerror(errno) );
      return EXIT_FAILURE;

      /* loop on decoding all events we have read */
      for( end=buf+size, fh=(struct fanotify_event_metadata *)(c=buf);
       c < end;
       c += fh->event_len, fh=(struct fanotify_event_metadata *)c )
      int n;
      unsigned u;
      uid_t uid;
      /* check fanotify metadata version */
      if(fh->vers != FANOTIFY_METADATA_VERSION)
          fprintf(stderr, "%s error: libc version of fanotify metadata"
              " does not match kernel's version.\n", progname);
          return EXIT_FAILURE;
      /* read command line from /proc */
      if( readproc(fh->pid, "cmdline", cmdline, sizeof(cmdline)) < 0 )
          fprintf( stderr, "%s cannot read processe's cmdline: %s\n",
               progname, strerror(errno) );
          return EXIT_FAILURE;
      /* read loginuid from /proc */
      if( readproc(fh->pid, "loginuid", loginuid, sizeof(loginuid)) < 0 )
          fprintf( stderr, "%s cannot read processe's loginuid: %s\n",
               progname, strerror(errno) );
          return EXIT_FAILURE;
      /* send permission */
      response.fd = fh->fd;
      response.response = FAN_ALLOW;
      if( write(fafd, &response, sizeof(response)) != sizeof(response) )
          fprintf( stderr, "%s error writing fanotify permission: %s\n",
               progname, strerror(errno) );
          return EXIT_FAILURE;

      /* decode user id and print log message */
        struct passwd *pw;
        /* we can't assume uid_t matches the size expectation of %u.
           Therefore we first decode the number into an unsigned and
           let the compiler automatically perform type conversion */
        sscanf(loginuid, "%u", &u);
        uid = u;
        pw = getpwuid(uid);
        if(pw) printf( "%s open by \"%s\" (pid=%u, owner=\"%s\")\n",
               argv[1], cmdline, fh->pid, pw->pw_name);
        else   printf( "%s open by \"%s\" (pid=%u, owner=%d)\n",
               argv[1], cmdline, fh->pid, uid);

ssize_t readproc(pid_t pid, const char *fname, char *buf, size_t len)
int pfd, n;
char procfn[256];

sprintf(procfn, "/proc/%d/%s", pid, fname);
pfd = open(procfn, O_RDONLY);
if(pfd < 0) return -1;
n = read( pfd, buf, len );
if(n<0) return -1;
buf[len] = '\0';
return n;