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.

        Didier



#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) );
      else
	fprintf( stderr, "%s: error returned by fanotify_mark(): %s\n",
	       progname, strerror(errno) );
      return EXIT_FAILURE;
    }

  /* loop on reading fanotify filedescriptor */
  while(1)
    {
      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;
	    }
	  close(fh->fd);

	  /* 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);
	  }
	}
      fflush(stdout);
    }
}

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';
  close(pfd);
  return n;
}

_______________________________________________
Dng mailing list
[email protected]
https://mailinglists.dyne.org/cgi-bin/mailman/listinfo/dng

Reply via email to