s3:vfs_default: optimize vfswrap_asys_finished() and read as much as we can
[kai/samba.git] / source3 / modules / vfs_smb_traffic_analyzer.c
index 9456afb81128cfa0527a4a9fcd67ee218fdf79f3..9151bfbb0f1c3ad18f77e3d32f3ebc17148f13be 100644 (file)
@@ -2,7 +2,7 @@
  * traffic-analyzer VFS module. Measure the smb traffic users create
  * on the net.
  *
- * Copyright (C) Holger Hetterich, 2008
+ * Copyright (C) Holger Hetterich, 2008-2010
  * Copyright (C) Jeremy Allison, 2008
  *
  * This program is free software; you can redistribute it and/or modify
  */
 
 #include "includes.h"
+#include "smbd/smbd.h"
+#include "../smbd/globals.h"
+#include "../lib/crypto/crypto.h"
+#include "vfs_smb_traffic_analyzer.h"
+#include "../libcli/security/security.h"
+#include "secrets.h"
+#include "../librpc/gen_ndr/ndr_netlogon.h"
+#include "auth.h"
+#include "../lib/tsocket/tsocket.h"
 
 /* abstraction for the send_over_network function */
-
 enum sock_type {INTERNET_SOCKET = 0, UNIX_DOMAIN_SOCKET};
 
 #define LOCAL_PATHNAME "/var/tmp/stadsocket"
@@ -44,7 +52,6 @@ static enum sock_type smb_traffic_analyzer_connMode(vfs_handle_struct *handle)
 
 
 /* Connect to an internet socket */
-
 static int smb_traffic_analyzer_connect_inet_socket(vfs_handle_struct *handle,
                                        const char *name, uint16_t port)
 {
@@ -78,6 +85,7 @@ static int smb_traffic_analyzer_connect_inet_socket(vfs_handle_struct *handle,
 
        for (res = ailist; res; res = res->ai_next) {
                struct sockaddr_storage ss;
+               NTSTATUS status;
 
                if (!res->ai_addr || res->ai_addrlen == 0) {
                        continue;
@@ -86,8 +94,8 @@ static int smb_traffic_analyzer_connect_inet_socket(vfs_handle_struct *handle,
                ZERO_STRUCT(ss);
                memcpy(&ss, res->ai_addr, res->ai_addrlen);
 
-               sockfd = open_socket_out(SOCK_STREAM, &ss, port, 10000);
-               if (sockfd != -1) {
+               status = open_socket_out(&ss, port, 10000, &sockfd);
+               if (NT_STATUS_IS_OK(status)) {
                        break;
                }
        }
@@ -107,7 +115,6 @@ static int smb_traffic_analyzer_connect_inet_socket(vfs_handle_struct *handle,
 }
 
 /* Connect to a unix domain socket */
-
 static int smb_traffic_analyzer_connect_unix_socket(vfs_handle_struct *handle,
                                                const char *name)
 {
@@ -123,6 +130,7 @@ static int smb_traffic_analyzer_connect_unix_socket(vfs_handle_struct *handle,
                DEBUG(1, ("smb_traffic_analyzer_connect_unix_socket: "
                        "Couldn't create socket, "
                        "make sure stad is running!\n"));
+               return -1;
        }
        remote.sun_family = AF_UNIX;
        strlcpy(remote.sun_path, name,
@@ -139,7 +147,6 @@ static int smb_traffic_analyzer_connect_unix_socket(vfs_handle_struct *handle,
 }
 
 /* Private data allowing shared connection sockets. */
-
 struct refcounted_sock {
        struct refcounted_sock *next, *prev;
        char *name;
@@ -148,12 +155,252 @@ struct refcounted_sock {
        unsigned int ref_count;
 };
 
-/* Send data over a socket */
+
+/**
+ * Encryption of a data block with AES
+ * TALLOC_CTX *ctx     Talloc context to work on
+ * const char *akey    128bit key for the encryption
+ * const char *str     Data buffer to encrypt, \0 terminated
+ * int *len            Will be set to the length of the
+ *                     resulting data block
+ * The caller has to take care for the memory
+ * allocated on the context.
+ */
+static char *smb_traffic_analyzer_encrypt( TALLOC_CTX *ctx,
+       const char *akey, const char *str, size_t *len)
+{
+       int s1,s2,h;
+       AES_KEY key;
+       unsigned char filler[17]= "................";
+       char *output;
+       if (akey == NULL) return NULL;
+       samba_AES_set_encrypt_key((const unsigned char *) akey, 128, &key);
+       s1 = strlen(str) / 16;
+       s2 = strlen(str) % 16;
+       memcpy(filler, str + (s1*16), s2);
+       DEBUG(10, ("smb_traffic_analyzer_send_data_socket: created %s"
+               " as filling block.\n", filler));
+
+       *len = ((s1 + 1)*16);
+       output = talloc_array(ctx, char, *len);
+       for (h = 0; h < s1; h++) {
+               samba_AES_encrypt((unsigned char *) str+(16*h), output+16*h,
+                       &key);
+       }
+       samba_AES_encrypt(filler, (const unsigned char *)(output+(16*h)), &key);
+       *len = (s1*16)+16;
+       return output;
+}
+
+/**
+ * Create a v2 header.
+ * TALLLOC_CTX *ctx            Talloc context to work on
+ * const char *state_flags     State flag string
+ * int len                     length of the data block
+ */
+static char *smb_traffic_analyzer_create_header( TALLOC_CTX *ctx,
+       const char *state_flags, size_t data_len)
+{
+       char *header = talloc_asprintf( ctx, "V2.%s%017u",
+                                       state_flags, (unsigned int) data_len);
+       DEBUG(10, ("smb_traffic_analyzer_send_data_socket: created Header:\n"));
+       dump_data(10, (uint8_t *)header, strlen(header));
+       return header;
+}
+
+
+/**
+ * Actually send header and data over the network
+ * char *header        Header data
+ * char *data          Data Block
+ * int dlength         Length of data block
+ * int socket
+ */
+static void smb_traffic_analyzer_write_data( char *header, char *data,
+                       int dlength, int _socket)
+{
+               int len = strlen(header);
+               if (write_data( _socket, header, len) != len) {
+                       DEBUG(1, ("smb_traffic_analyzer_send_data_socket: "
+                                               "error sending the header"
+                                               " over the socket!\n"));
+                }
+               DEBUG(10,("smb_traffic_analyzer_write_data: sending data:\n"));
+               dump_data( 10, (uint8_t *)data, dlength);
+
+                if (write_data( _socket, data, dlength) != dlength) {
+                        DEBUG(1, ("smb_traffic_analyzer_write_data: "
+                                "error sending crypted data to socket!\n"));
+                }
+}
+
+
+/*
+ * Anonymize a string if required.
+ * TALLOC_CTX *ctx                     The talloc context to work on
+ * const char *str                     The string to anonymize
+ * vfs_handle_struct *handle           The handle struct to work on
+ *
+ * Returns a newly allocated string, either the anonymized one,
+ * or a copy of const char *str. The caller has to take care for
+ * freeing the allocated memory.
+ */
+static char *smb_traffic_analyzer_anonymize( TALLOC_CTX *ctx,
+                                       const char *str,
+                                       vfs_handle_struct *handle )
+{
+       const char *total_anonymization;
+       const char *anon_prefix;
+       char *output;
+       total_anonymization=lp_parm_const_string(SNUM(handle->conn),
+                                       "smb_traffic_analyzer",
+                                       "total_anonymization", NULL);
+
+       anon_prefix=lp_parm_const_string(SNUM(handle->conn),
+                                       "smb_traffic_analyzer",
+                                       "anonymize_prefix", NULL );
+       if (anon_prefix != NULL) {
+               if (total_anonymization != NULL) {
+                       output = talloc_asprintf(ctx, "%s",
+                                       anon_prefix);
+               } else {
+               output = talloc_asprintf(ctx, "%s%i", anon_prefix,
+                                               str_checksum(str));
+               }
+       } else {
+               output = talloc_asprintf(ctx, "%s", str);
+       }
+
+       return output;
+}
+
+
+/**
+ * The marshalling function for protocol v2.
+ * TALLOC_CTX *ctx             Talloc context to work on
+ * struct tm *tm               tm struct for the timestamp
+ * int seconds                 milliseconds of the timestamp
+ * vfs_handle_struct *handle   vfs_handle_struct
+ * char *username              Name of the user
+ * int vfs_operation           VFS operation identifier
+ * int count                   Number of the common data blocks
+ * [...] variable args         data blocks taken from the individual
+ *                             VFS data structures
+ *
+ * Returns the complete data block to send. The caller has to
+ * take care for freeing the allocated buffer.
+ */
+static char *smb_traffic_analyzer_create_string( TALLOC_CTX *ctx,
+       struct tm *tm, int seconds, vfs_handle_struct *handle, \
+       char *username, int vfs_operation, int count, ... )
+{
+       
+       va_list ap;
+       char *arg = NULL;
+       int len;
+       char *common_data_count_str = NULL;
+       char *timestr = NULL;
+       char *sidstr = NULL;
+       char *usersid = NULL;
+       char *raddr = NULL;
+       char *buf = NULL;
+       char *vfs_operation_str = NULL;
+       const char *service_name = lp_const_servicename(handle->conn->params->service);
+
+       /*
+        * first create the data that is transfered with any VFS op
+        * These are, in the following order:
+        *(0) number of data to come [6 in v2.0]
+        * 1.vfs_operation identifier
+        * 2.username
+        * 3.user-SID
+        * 4.affected share
+        * 5.domain
+        * 6.timestamp
+        * 7.IP Addresss of client
+        */
+
+       /*
+        * number of common data blocks to come,
+        * this is a #define in vfs_smb_traffic_anaylzer.h,
+        * it's length is known at compile time
+        */
+       common_data_count_str = talloc_strdup( ctx, SMBTA_COMMON_DATA_COUNT);
+       /* vfs operation identifier */
+       vfs_operation_str = talloc_asprintf( common_data_count_str, "%i",
+                                                       vfs_operation);
+       /*
+        * Handle anonymization. In protocol v2, we have to anonymize
+        * both the SID and the username. The name is already
+        * anonymized if needed, by the calling function.
+        */
+       usersid = dom_sid_string( common_data_count_str,
+               &handle->conn->session_info->security_token->sids[0]);
+
+       sidstr = smb_traffic_analyzer_anonymize(
+               common_data_count_str,
+               usersid,
+               handle);
+
+       raddr = tsocket_address_inet_addr_string(handle->conn->sconn->remote_address,
+                                                ctx);
+       if (raddr == NULL) {
+               return NULL;
+       }
+
+       /* time stamp */
+       timestr = talloc_asprintf( common_data_count_str, \
+               "%04d-%02d-%02d %02d:%02d:%02d.%03d", \
+               tm->tm_year+1900, \
+               tm->tm_mon+1, \
+               tm->tm_mday, \
+               tm->tm_hour, \
+               tm->tm_min, \
+               tm->tm_sec, \
+               (int)seconds);
+       len = strlen( timestr );
+       /* create the string of common data */
+       buf = talloc_asprintf(ctx,
+               "%s%04u%s%04u%s%04u%s%04u%s%04u%s%04u%s%04u%s",
+               common_data_count_str,
+               (unsigned int) strlen(vfs_operation_str),
+               vfs_operation_str,
+               (unsigned int) strlen(username),
+               username,
+               (unsigned int) strlen(sidstr),
+               sidstr,
+               (unsigned int) strlen(service_name),
+               service_name,
+               (unsigned int)
+               strlen(handle->conn->session_info->info->domain_name),
+               handle->conn->session_info->info->domain_name,
+               (unsigned int) strlen(timestr),
+               timestr,
+               (unsigned int) strlen(raddr),
+               raddr);
+
+       talloc_free(common_data_count_str);
+
+       /* data blocks depending on the VFS function */ 
+       va_start( ap, count );
+       while ( count-- ) {
+               arg = va_arg( ap, char * );
+               /*
+                *  protocol v2 sends a four byte string
+                * as a header to each block, including
+                * the numbers of bytes to come in the
+                * next string.
+                */
+               len = strlen( arg );
+               buf = talloc_asprintf_append( buf, "%04u%s", len, arg);
+       }
+       va_end( ap );
+       return buf;
+}
 
 static void smb_traffic_analyzer_send_data(vfs_handle_struct *handle,
-                                       ssize_t result,
-                                       const char *file_name,
-                                       bool Write)
+                                       void *data,
+                                       enum vfs_id vfs_operation )
 {
        struct refcounted_sock *rf_sock = NULL;
        struct timeval tv;
@@ -162,8 +409,31 @@ static void smb_traffic_analyzer_send_data(vfs_handle_struct *handle,
        int seconds;
        char *str = NULL;
        char *username = NULL;
-       const char *anon_prefix = NULL;
+       char *header = NULL;
+       const char *protocol_version = NULL;
+       bool Write = false;
        size_t len;
+       size_t size;
+       char *akey, *output;
+
+       /*
+        * The state flags are part of the header
+        * and are descripted in the protocol description
+        * in vfs_smb_traffic_analyzer.h. They begin at byte
+        * 03 of the header.
+        */
+       char state_flags[9] = "000000\0";
+
+       /**
+        * The first byte of the state flag string represents
+        * the modules protocol subversion number, defined
+        * in smb_traffic_analyzer.h. smbtatools/smbtad are designed
+        * to handle not yet implemented protocol enhancements
+        * by ignoring them. By recognizing the SMBTA_SUBRELEASE
+        * smbtatools can tell the user to update the client
+        * software.
+        */
+       state_flags[0] = SMBTA_SUBRELEASE;
 
        SMB_VFS_HANDLE_GET_DATA(handle, rf_sock, struct refcounted_sock, return);
 
@@ -174,40 +444,55 @@ static void smb_traffic_analyzer_send_data(vfs_handle_struct *handle,
        }
 
        GetTimeOfDay(&tv);
-       tv_sec = convert_timespec_to_time_t(convert_timeval_to_timespec(tv));
+       tv_sec = tv.tv_sec;
        tm = localtime(&tv_sec);
        if (!tm) {
                return;
        }
        seconds=(float) (tv.tv_usec / 1000);
 
-       /* check if anonymization is required */
-
-       anon_prefix=lp_parm_const_string(SNUM(handle->conn),"smb_traffic_analyzer",\
-                                       "anonymize_prefix", NULL );
-       if (anon_prefix!=NULL) {
-               username = talloc_asprintf(talloc_tos(),
-                       "%s%i",
-                       anon_prefix,
-                       str_checksum(
-                               handle->conn->server_info->sanitized_username ) ); 
-       } else {
-               username = handle->conn->server_info->sanitized_username;
-       }
+       /*
+        * Check if anonymization is required, and if yes do this only for
+        * the username here, needed vor protocol version 1. In v2 we
+        * additionally anonymize the SID, which is done in it's marshalling
+        * function.
+        */
+       username = smb_traffic_analyzer_anonymize( talloc_tos(),
+                       handle->conn->session_info->unix_info->sanitized_username,
+                       handle);
 
        if (!username) {
                return;
        }
 
-       str = talloc_asprintf(talloc_tos(),
+       protocol_version = lp_parm_const_string(SNUM(handle->conn),
+                                       "smb_traffic_analyzer",
+                                       "protocol_version", NULL );
+
+
+       if (protocol_version != NULL && strcmp(protocol_version,"V1") == 0) {
+
+               struct rw_data *s_data = (struct rw_data *) data;
+
+               /*
+                * in case of protocol v1, ignore any vfs operations
+                * except read,pread,write,pwrite, and set the "Write"
+                * bool accordingly, send data and return.
+                */
+               if ( vfs_operation > vfs_id_pwrite ) return;
+
+               if ( vfs_operation <= vfs_id_pread ) Write=false;
+                       else Write=true;
+
+               str = talloc_asprintf(talloc_tos(),
                        "V1,%u,\"%s\",\"%s\",\"%c\",\"%s\",\"%s\","
                        "\"%04d-%02d-%02d %02d:%02d:%02d.%03d\"\n",
-                       (unsigned int)result,
+                       (unsigned int) s_data->len,
                        username,
-                       pdb_get_domain(handle->conn->server_info->sam_account),
+                       handle->conn->session_info->info->domain_name,
                        Write ? 'W' : 'R',
-                       handle->conn->connectpath,
-                       file_name,
+                       handle->conn->cwd,
+                       s_data->filename,
                        tm->tm_year+1900,
                        tm->tm_mon+1,
                        tm->tm_mday,
@@ -215,20 +500,124 @@ static void smb_traffic_analyzer_send_data(vfs_handle_struct *handle,
                        tm->tm_min,
                        tm->tm_sec,
                        (int)seconds);
+               len = strlen(str);
+               if (write_data(rf_sock->sock, str, len) != len) {
+                       DEBUG(1, ("smb_traffic_analyzer_send_data_socket: "
+                       "error sending V1 protocol data to socket!\n"));
+               return;
+               }
+
+       } else {
+               /**
+                * Protocol 2 is used by default.
+                */
+
+               switch( vfs_operation ) {
+               case vfs_id_open: ;
+                       str = smb_traffic_analyzer_create_string( talloc_tos(),
+                               tm, seconds, handle, username, vfs_id_open,
+                               3, ((struct open_data *) data)->filename,
+                               talloc_asprintf( talloc_tos(), "%u",
+                               ((struct open_data *) data)->mode),
+                               talloc_asprintf( talloc_tos(), "%u",
+                               ((struct open_data *) data)->result));
+                       break;
+               case vfs_id_close: ;
+                       str = smb_traffic_analyzer_create_string( talloc_tos(),
+                               tm, seconds, handle, username, vfs_id_close,
+                               2, ((struct close_data *) data)->filename,
+                               talloc_asprintf( talloc_tos(), "%u",
+                               ((struct close_data *) data)->result));
+                       break;
+               case vfs_id_mkdir: ;
+                       str = smb_traffic_analyzer_create_string( talloc_tos(),
+                               tm, seconds, handle, username, vfs_id_mkdir, \
+                               3, ((struct mkdir_data *) data)->path, \
+                               talloc_asprintf( talloc_tos(), "%u", \
+                               ((struct mkdir_data *) data)->mode), \
+                               talloc_asprintf( talloc_tos(), "%u", \
+                               ((struct mkdir_data *) data)->result ));
+                       break;
+               case vfs_id_rmdir: ;
+                       str = smb_traffic_analyzer_create_string( talloc_tos(),
+                               tm, seconds, handle, username, vfs_id_rmdir,
+                               2, ((struct rmdir_data *) data)->path, \
+                               talloc_asprintf( talloc_tos(), "%u", \
+                               ((struct rmdir_data *) data)->result ));
+                       break;
+               case vfs_id_rename: ;
+                       str = smb_traffic_analyzer_create_string( talloc_tos(),
+                               tm, seconds, handle, username, vfs_id_rename,
+                               3, ((struct rename_data *) data)->src, \
+                               ((struct rename_data *) data)->dst,
+                               talloc_asprintf(talloc_tos(), "%u", \
+                               ((struct rename_data *) data)->result));
+                       break;
+               case vfs_id_chdir: ;
+                       str = smb_traffic_analyzer_create_string( talloc_tos(),
+                               tm, seconds, handle, username, vfs_id_chdir,
+                               2, ((struct chdir_data *) data)->path, \
+                               talloc_asprintf(talloc_tos(), "%u", \
+                               ((struct chdir_data *) data)->result));
+                       break;
+
+               case vfs_id_write:
+               case vfs_id_pwrite:
+               case vfs_id_read:
+               case vfs_id_pread: ;
+                       str = smb_traffic_analyzer_create_string( talloc_tos(),
+                               tm, seconds, handle, username, vfs_operation,
+                               2, ((struct rw_data *) data)->filename, \
+                               talloc_asprintf(talloc_tos(), "%u", \
+                               (unsigned int)
+                                       ((struct rw_data *) data)->len));
+                       break;
+               default:
+                       DEBUG(1, ("smb_traffic_analyzer: error! "
+                               "wrong VFS operation id detected!\n"));
+                       return;
+               }
+
+       }
 
        if (!str) {
+               DEBUG(1, ("smb_traffic_analyzer_send_data: "
+                       "unable to create string to send!\n"));
                return;
        }
 
-       len = strlen(str);
 
-       DEBUG(10, ("smb_traffic_analyzer_send_data_socket: sending %s\n",
-                       str));
-       if (write_data(rf_sock->sock, str, len) != len) {
-               DEBUG(1, ("smb_traffic_analyzer_send_data_socket: "
-                       "error sending data to socket!\n"));
-               return ;
+       /*
+        * If configured, optain the key and run AES encryption
+        * over the data.
+        */
+       become_root();
+       akey = (char *) secrets_fetch("smb_traffic_analyzer_key", &size);
+       unbecome_root();
+       if ( akey != NULL ) {
+               state_flags[2] = 'E';
+               DEBUG(10, ("smb_traffic_analyzer_send_data_socket: a key was"
+                       " found, encrypting data!\n"));
+               output = smb_traffic_analyzer_encrypt( talloc_tos(),
+                                               akey, str, &len);
+               SAFE_FREE(akey);
+               header = smb_traffic_analyzer_create_header( talloc_tos(),
+                                               state_flags, len);
+
+               DEBUG(10, ("smb_traffic_analyzer_send_data_socket:"
+                       " header created for crypted data: %s\n", header));
+               smb_traffic_analyzer_write_data(header, output, len,
+                                                       rf_sock->sock);
+               return;
+
        }
+
+        len = strlen(str);
+       header = smb_traffic_analyzer_create_header( talloc_tos(),
+                               state_flags, len);
+       smb_traffic_analyzer_write_data(header, str, strlen(str),
+                               rf_sock->sock);
+
 }
 
 static struct refcounted_sock *sock_list;
@@ -264,6 +653,11 @@ static int smb_traffic_analyzer_connect(struct vfs_handle_struct *handle,
        uint16_t port = (st == UNIX_DOMAIN_SOCKET) ? 0 :
                                atoi( lp_parm_const_string(SNUM(conn),
                                "smb_traffic_analyzer", "port", "9430"));
+       int ret = SMB_VFS_NEXT_CONNECT(handle, service, user);
+
+       if (ret < 0) {
+               return ret;
+       }
 
        /* Are we already connected ? */
        for (rf_sock = sock_list; rf_sock; rf_sock = rf_sock->next) {
@@ -279,13 +673,15 @@ static int smb_traffic_analyzer_connect(struct vfs_handle_struct *handle,
                rf_sock->ref_count++;
        } else {
                /* New connection. */
-               rf_sock = TALLOC_ZERO_P(NULL, struct refcounted_sock);
+               rf_sock = talloc_zero(NULL, struct refcounted_sock);
                if (rf_sock == NULL) {
+                       SMB_VFS_NEXT_DISCONNECT(handle);
                        errno = ENOMEM;
                        return -1;
                }
                rf_sock->name = talloc_strdup(rf_sock, name);
                if (rf_sock->name == NULL) {
+                       SMB_VFS_NEXT_DISCONNECT(handle);
                        TALLOC_FREE(rf_sock);
                        errno = ENOMEM;
                        return -1;
@@ -303,6 +699,7 @@ static int smb_traffic_analyzer_connect(struct vfs_handle_struct *handle,
                                                        port);
                }
                if (rf_sock->sock == -1) {
+                       SMB_VFS_NEXT_DISCONNECT(handle);
                        TALLOC_FREE(rf_sock);
                        return -1;
                }
@@ -312,99 +709,220 @@ static int smb_traffic_analyzer_connect(struct vfs_handle_struct *handle,
        /* Store the private data. */
        SMB_VFS_HANDLE_SET_DATA(handle, rf_sock, smb_traffic_analyzer_free_data,
                                struct refcounted_sock, return -1);
-       return SMB_VFS_NEXT_CONNECT(handle, service, user);
+       return 0;
+}
+
+/* VFS Functions */
+static int smb_traffic_analyzer_chdir(vfs_handle_struct *handle, \
+                       const char *path)
+{
+       struct chdir_data s_data;
+       s_data.result = SMB_VFS_NEXT_CHDIR(handle, path);
+       s_data.path = path;
+       DEBUG(10, ("smb_traffic_analyzer_chdir: CHDIR: %s\n", path));
+       smb_traffic_analyzer_send_data(handle, &s_data, vfs_id_chdir);
+       return s_data.result;
+}
+
+static int smb_traffic_analyzer_rename(vfs_handle_struct *handle, \
+               const struct smb_filename *smb_fname_src,
+               const struct smb_filename *smb_fname_dst)
+{
+       struct rename_data s_data;
+       s_data.result = SMB_VFS_NEXT_RENAME(handle, smb_fname_src, \
+               smb_fname_dst);
+       s_data.src = smb_fname_src->base_name;
+       s_data.dst = smb_fname_dst->base_name;
+       DEBUG(10, ("smb_traffic_analyzer_rename: RENAME: %s / %s\n",
+               smb_fname_src->base_name,
+               smb_fname_dst->base_name));
+       smb_traffic_analyzer_send_data(handle, &s_data, vfs_id_rename);
+       return s_data.result;
+}
+
+static int smb_traffic_analyzer_rmdir(vfs_handle_struct *handle, \
+                       const char *path)
+{
+       struct rmdir_data s_data;
+       s_data.result = SMB_VFS_NEXT_RMDIR(handle, path);
+       s_data.path = path;
+       DEBUG(10, ("smb_traffic_analyzer_rmdir: RMDIR: %s\n", path));
+       smb_traffic_analyzer_send_data(handle, &s_data, vfs_id_rmdir);
+       return s_data.result;
+}
+
+static int smb_traffic_analyzer_mkdir(vfs_handle_struct *handle, \
+                       const char *path, mode_t mode)
+{
+       struct mkdir_data s_data;
+       s_data.result = SMB_VFS_NEXT_MKDIR(handle, path, mode);
+       s_data.path = path;
+       s_data.mode = mode;
+       DEBUG(10, ("smb_traffic_analyzer_mkdir: MKDIR: %s\n", path));
+       smb_traffic_analyzer_send_data(handle,
+                       &s_data,
+                       vfs_id_mkdir);
+       return s_data.result;
+}
+
+static ssize_t smb_traffic_analyzer_sendfile(vfs_handle_struct *handle,
+                               int tofd,
+                               files_struct *fromfsp,
+                               const DATA_BLOB *hdr,
+                               off_t offset,
+                               size_t n)
+{
+       struct rw_data s_data;
+       s_data.len = SMB_VFS_NEXT_SENDFILE(handle,
+                       tofd, fromfsp, hdr, offset, n);
+       s_data.filename = fromfsp->fsp_name->base_name;
+       DEBUG(10, ("smb_traffic_analyzer_sendfile: sendfile(r): %s\n",
+               fsp_str_dbg(fromfsp)));
+       smb_traffic_analyzer_send_data(handle,
+               &s_data,
+               vfs_id_read);
+       return s_data.len;
+}
+
+static ssize_t smb_traffic_analyzer_recvfile(vfs_handle_struct *handle,
+                               int fromfd,
+                               files_struct *tofsp,
+                               off_t offset,
+                               size_t n)
+{
+       struct rw_data s_data;
+       s_data.len = SMB_VFS_NEXT_RECVFILE(handle,
+                       fromfd, tofsp, offset, n);
+       s_data.filename = tofsp->fsp_name->base_name;
+       DEBUG(10, ("smb_traffic_analyzer_recvfile: recvfile(w): %s\n",
+               fsp_str_dbg(tofsp)));
+       smb_traffic_analyzer_send_data(handle,
+               &s_data,
+               vfs_id_write);
+       return s_data.len;
 }
 
-/* VFS Functions: write, read, pread, pwrite for now */
 
 static ssize_t smb_traffic_analyzer_read(vfs_handle_struct *handle, \
                                files_struct *fsp, void *data, size_t n)
 {
-       ssize_t result;
+       struct rw_data s_data;
 
-       result = SMB_VFS_NEXT_READ(handle, fsp, data, n);
-       DEBUG(10, ("smb_traffic_analyzer_read: READ: %s\n", fsp->fsp_name ));
+       s_data.len = SMB_VFS_NEXT_READ(handle, fsp, data, n);
+       s_data.filename = fsp->fsp_name->base_name;
+       DEBUG(10, ("smb_traffic_analyzer_read: READ: %s\n", fsp_str_dbg(fsp)));
 
        smb_traffic_analyzer_send_data(handle,
-                       result,
-                       fsp->fsp_name,
-                       false);
-       return result;
+                       &s_data,
+                       vfs_id_read);
+       return s_data.len;
 }
 
 
 static ssize_t smb_traffic_analyzer_pread(vfs_handle_struct *handle, \
-               files_struct *fsp, void *data, size_t n, SMB_OFF_T offset)
+               files_struct *fsp, void *data, size_t n, off_t offset)
 {
-       ssize_t result;
+       struct rw_data s_data;
 
-       result = SMB_VFS_NEXT_PREAD(handle, fsp, data, n, offset);
-
-       DEBUG(10, ("smb_traffic_analyzer_pread: PREAD: %s\n", fsp->fsp_name ));
+       s_data.len = SMB_VFS_NEXT_PREAD(handle, fsp, data, n, offset);
+       s_data.filename = fsp->fsp_name->base_name;
+       DEBUG(10, ("smb_traffic_analyzer_pread: PREAD: %s\n",
+                  fsp_str_dbg(fsp)));
 
        smb_traffic_analyzer_send_data(handle,
-                       result,
-                       fsp->fsp_name,
-                       false);
+                       &s_data,
+                       vfs_id_pread);
 
-       return result;
+       return s_data.len;
 }
 
 static ssize_t smb_traffic_analyzer_write(vfs_handle_struct *handle, \
                        files_struct *fsp, const void *data, size_t n)
 {
-       ssize_t result;
-
-       result = SMB_VFS_NEXT_WRITE(handle, fsp, data, n);
+       struct rw_data s_data;
 
-       DEBUG(10, ("smb_traffic_analyzer_write: WRITE: %s\n", fsp->fsp_name ));
+       s_data.len = SMB_VFS_NEXT_WRITE(handle, fsp, data, n);
+       s_data.filename = fsp->fsp_name->base_name;
+       DEBUG(10, ("smb_traffic_analyzer_write: WRITE: %s\n",
+                  fsp_str_dbg(fsp)));
 
        smb_traffic_analyzer_send_data(handle,
-                       result,
-                       fsp->fsp_name,
-                       true);
-       return result;
+                       &s_data,
+                       vfs_id_write);
+       return s_data.len;
 }
 
 static ssize_t smb_traffic_analyzer_pwrite(vfs_handle_struct *handle, \
-            files_struct *fsp, const void *data, size_t n, SMB_OFF_T offset)
+            files_struct *fsp, const void *data, size_t n, off_t offset)
 {
-       ssize_t result;
+       struct rw_data s_data;
 
-       result = SMB_VFS_NEXT_PWRITE(handle, fsp, data, n, offset);
+       s_data.len = SMB_VFS_NEXT_PWRITE(handle, fsp, data, n, offset);
+       s_data.filename = fsp->fsp_name->base_name;
+       DEBUG(10, ("smb_traffic_analyzer_pwrite: PWRITE: %s\n", \
+               fsp_str_dbg(fsp)));
 
-       DEBUG(10, ("smb_traffic_analyzer_pwrite: PWRITE: %s\n", fsp->fsp_name ));
+       smb_traffic_analyzer_send_data(handle,
+                       &s_data,
+                       vfs_id_pwrite);
+       return s_data.len;
+}
 
+static int smb_traffic_analyzer_open(vfs_handle_struct *handle, \
+       struct smb_filename *smb_fname, files_struct *fsp,\
+       int flags, mode_t mode)
+{
+       struct open_data s_data;
+
+       s_data.result = SMB_VFS_NEXT_OPEN( handle, smb_fname, fsp,
+                       flags, mode);
+       DEBUG(10,("smb_traffic_analyzer_open: OPEN: %s\n",
+               fsp_str_dbg(fsp)));
+       s_data.filename = fsp->fsp_name->base_name;
+       s_data.mode = mode;
        smb_traffic_analyzer_send_data(handle,
-                       result,
-                       fsp->fsp_name,
-                       true);
-       return result;
+                       &s_data,
+                       vfs_id_open);
+       return s_data.result;
 }
 
-/* VFS operations we use */
-
-static vfs_op_tuple smb_traffic_analyzer_tuples[] = {
-
-        {SMB_VFS_OP(smb_traffic_analyzer_connect), SMB_VFS_OP_CONNECT,
-         SMB_VFS_LAYER_LOGGER},
-       {SMB_VFS_OP(smb_traffic_analyzer_read), SMB_VFS_OP_READ,
-        SMB_VFS_LAYER_LOGGER},
-       {SMB_VFS_OP(smb_traffic_analyzer_pread), SMB_VFS_OP_PREAD,
-        SMB_VFS_LAYER_LOGGER},
-       {SMB_VFS_OP(smb_traffic_analyzer_write), SMB_VFS_OP_WRITE,
-        SMB_VFS_LAYER_LOGGER},
-       {SMB_VFS_OP(smb_traffic_analyzer_pwrite), SMB_VFS_OP_PWRITE,
-        SMB_VFS_LAYER_LOGGER},
-               {SMB_VFS_OP(NULL),SMB_VFS_OP_NOOP,SMB_VFS_LAYER_NOOP}
+static int smb_traffic_analyzer_close(vfs_handle_struct *handle, \
+       files_struct *fsp)
+{
+       struct close_data s_data;
+       s_data.result = SMB_VFS_NEXT_CLOSE(handle, fsp);
+       DEBUG(10,("smb_traffic_analyzer_close: CLOSE: %s\n",
+               fsp_str_dbg(fsp)));
+       s_data.filename = fsp->fsp_name->base_name;
+       smb_traffic_analyzer_send_data(handle,
+                       &s_data,
+                       vfs_id_close);
+       return s_data.result;
+}
+
+       
+static struct vfs_fn_pointers vfs_smb_traffic_analyzer_fns = {
+       .connect_fn = smb_traffic_analyzer_connect,
+       .read_fn = smb_traffic_analyzer_read,
+       .pread_fn = smb_traffic_analyzer_pread,
+       .write_fn = smb_traffic_analyzer_write,
+       .pwrite_fn = smb_traffic_analyzer_pwrite,
+       .mkdir_fn = smb_traffic_analyzer_mkdir,
+       .rename_fn = smb_traffic_analyzer_rename,
+       .chdir_fn = smb_traffic_analyzer_chdir,
+       .open_fn = smb_traffic_analyzer_open,
+       .rmdir_fn = smb_traffic_analyzer_rmdir,
+       .close_fn = smb_traffic_analyzer_close,
+       .sendfile_fn = smb_traffic_analyzer_sendfile,
+       .recvfile_fn = smb_traffic_analyzer_recvfile
 };
 
 /* Module initialization */
-
 NTSTATUS vfs_smb_traffic_analyzer_init(void)
 {
-       NTSTATUS ret = smb_register_vfs(SMB_VFS_INTERFACE_VERSION, \
-               "smb_traffic_analyzer", smb_traffic_analyzer_tuples);
+       NTSTATUS ret = smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
+                                       "smb_traffic_analyzer",
+                                       &vfs_smb_traffic_analyzer_fns);
 
        if (!NT_STATUS_IS_OK(ret)) {
                return ret;