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;
}