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'
The program can be compiled with 'gcc -o fawatch fawatch.c'
You need special permission to execute the program. Being root is
the simplest way.
I'm going to start it from rc.local, just to see ...
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;
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;
}
sscanf(loginuid, "%u", &uid);
/* 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);
{
struct passwd *pw;
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';
close(pfd);
return n;
}