Implement anonymization for protocol v2.
[amitay/samba.git] / source3 / modules / vfs_smb_traffic_analyzer.c
1 /*
2  * traffic-analyzer VFS module. Measure the smb traffic users create
3  * on the net.
4  *
5  * Copyright (C) Holger Hetterich, 2008
6  * Copyright (C) Jeremy Allison, 2008
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, see <http://www.gnu.org/licenses/>.
20  */
21
22 #include "includes.h"
23 #include "../lib/crypto/crypto.h"
24
25 /* abstraction for the send_over_network function */
26 enum sock_type {INTERNET_SOCKET = 0, UNIX_DOMAIN_SOCKET};
27
28 #define LOCAL_PATHNAME "/var/tmp/stadsocket"
29
30
31 /**
32  * Protocol version 2.0 description
33  *
34  * The following table shows the exact assembly of the 2.0 protocol.
35  *
36  * -->Header<--
37  * The protocol header is always send first, and contains various
38  * information about the data block to come.
39  * The header is always of fixed length, and will be send unencrypted.
40  *
41  * Byte Number/Bytes    Description
42  * 00-02                Contains always the string "V2."
43  * 03                   This byte contains a possible subrelease number of the
44  *                      protocol. This enables the receiver to make a version
45  *                      check to ensure the compatibility and allows us to
46  *                      release 2.x versions of the protocol with bugfixes or
47  *                      enhancements.
48  * 04                   This byte is reserved for possible future extensions.
49  * 05                   Usually, this byte contains the character '0'. If the
50  *                      VFS module is configured for encryption of the data,
51  *                      this byte is set to 'E'.
52  * 06-09                These bytes contain the character '0' by default, and
53  *                      are reserved for possible future extensions. They have
54  *                      no function in 2.0.
55  * 10-27                17 bytes containing a string representation of the
56  *                      number of bytes to come in the following data block.
57  *                      It is right aligned and filled from the left with '0'.
58  * 
59  * -->Data Block<--
60  * The data block is send immediately after the header was send. It's length
61  * is exactly what was given in bytes 11-28 from in the header.
62  *
63  * The data block may be send encrypted.
64  * 
65  * To make the data block easy for the receiver to read, it is divided into
66  * several sub-blocks, each with it's own header of four byte length. In each
67  * of the sub-headers, a string representation of the length of this block is
68  * to be found.
69  *
70  * Thus the formal structure is very simple:
71  *
72  * [HEADER]data[HEADER]data[HEADER]data[END]
73  *
74  * whereas [END] is exactly at the position given in bytes 11-28 of the
75  * header.
76  *
77  * Some data the VFS module is capturing is of use for any VFS operation.
78  * Therefore, there is a "common set" of data, that will be send with any
79  * data block. The following provides a list of this data.
80  * - the VFS function identifier (see VFS function ifentifier table below).
81  * - a timestamp to the millisecond.
82  * - the username (as text) who runs the VFS operation.
83  * - the SID of the user who run the VFS operation.
84  * - the domain under which the VFS operation has happened.
85  *
86  */
87
88  
89 /** 
90  * VFS Functions identifier table. In protocol version 2, every vfs
91  * function is given a unique id.
92  */
93 enum vfs_id {
94         /*
95          * care for the order here, required for compatibility
96          * with protocol version 1.
97          */
98         vfs_id_read,
99         vfs_id_pread,
100         vfs_id_write,
101         vfs_id_pwrite,
102         /* end of protocol version 1 identifiers. */
103         vfs_id_mkdir,
104         vfs_id_rmdir,
105         vfs_id_rename,
106         vfs_id_chdir
107 };
108
109 /*
110  * Specific data sets for the VFS functions.
111  * A compatible receiver has to have the exact same dataset.
112  */
113 struct mkdir_data {
114         const char *path;
115         mode_t mode;
116         int result;
117 };
118
119 struct rmdir_data {
120         const char *path;
121         int result;
122 };
123
124 struct rename_data {
125         const char *src;
126         const char *dst;
127         int result;
128 };
129
130 struct chdir_data {
131         const char *path;
132         int result;
133 };
134         
135 /* rw_data used for read/write/pread/pwrite */
136 struct rw_data {
137         char *filename;
138         size_t len;
139 };
140
141 static int vfs_smb_traffic_analyzer_debug_level = DBGC_VFS;
142
143 static enum sock_type smb_traffic_analyzer_connMode(vfs_handle_struct *handle)
144 {
145         connection_struct *conn = handle->conn;
146         const char *Mode;
147         Mode=lp_parm_const_string(SNUM(conn), "smb_traffic_analyzer","mode", \
148                         "internet_socket");
149         if (strstr(Mode,"unix_domain_socket")) {
150                 return UNIX_DOMAIN_SOCKET;
151         } else {
152                 return INTERNET_SOCKET;
153         }
154 }
155
156
157 /* Connect to an internet socket */
158 static int smb_traffic_analyzer_connect_inet_socket(vfs_handle_struct *handle,
159                                         const char *name, uint16_t port)
160 {
161         /* Create a streaming Socket */
162         int sockfd = -1;
163         struct addrinfo hints;
164         struct addrinfo *ailist = NULL;
165         struct addrinfo *res = NULL;
166         int ret;
167
168         ZERO_STRUCT(hints);
169         /* By default make sure it supports TCP. */
170         hints.ai_socktype = SOCK_STREAM;
171         hints.ai_flags = AI_ADDRCONFIG;
172
173         ret = getaddrinfo(name,
174                         NULL,
175                         &hints,
176                         &ailist);
177
178         if (ret) {
179                 DEBUG(3,("smb_traffic_analyzer_connect_inet_socket: "
180                         "getaddrinfo failed for name %s [%s]\n",
181                         name,
182                         gai_strerror(ret) ));
183                 return -1;
184         }
185
186         DEBUG(3,("smb_traffic_analyzer: Internet socket mode. Hostname: %s,"
187                 "Port: %i\n", name, port));
188
189         for (res = ailist; res; res = res->ai_next) {
190                 struct sockaddr_storage ss;
191                 NTSTATUS status;
192
193                 if (!res->ai_addr || res->ai_addrlen == 0) {
194                         continue;
195                 }
196
197                 ZERO_STRUCT(ss);
198                 memcpy(&ss, res->ai_addr, res->ai_addrlen);
199
200                 status = open_socket_out(&ss, port, 10000, &sockfd);
201                 if (NT_STATUS_IS_OK(status)) {
202                         break;
203                 }
204         }
205
206         if (ailist) {
207                 freeaddrinfo(ailist);
208         }
209
210         if (sockfd == -1) {
211                 DEBUG(1, ("smb_traffic_analyzer: unable to create "
212                         "socket, error is %s",
213                         strerror(errno)));
214                 return -1;
215         }
216
217         return sockfd;
218 }
219
220 /* Connect to a unix domain socket */
221 static int smb_traffic_analyzer_connect_unix_socket(vfs_handle_struct *handle,
222                                                 const char *name)
223 {
224         /* Create the socket to stad */
225         int len, sock;
226         struct sockaddr_un remote;
227
228         DEBUG(7, ("smb_traffic_analyzer_connect_unix_socket: "
229                         "Unix domain socket mode. Using %s\n",
230                         name ));
231
232         if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
233                 DEBUG(1, ("smb_traffic_analyzer_connect_unix_socket: "
234                         "Couldn't create socket, "
235                         "make sure stad is running!\n"));
236                 return -1;
237         }
238         remote.sun_family = AF_UNIX;
239         strlcpy(remote.sun_path, name,
240                     sizeof(remote.sun_path));
241         len=strlen(remote.sun_path) + sizeof(remote.sun_family);
242         if (connect(sock, (struct sockaddr *)&remote, len) == -1 ) {
243                 DEBUG(1, ("smb_traffic_analyzer_connect_unix_socket: "
244                         "Could not connect to "
245                         "socket, make sure\nstad is running!\n"));
246                 close(sock);
247                 return -1;
248         }
249         return sock;
250 }
251
252 /* Private data allowing shared connection sockets. */
253 struct refcounted_sock {
254         struct refcounted_sock *next, *prev;
255         char *name;
256         uint16_t port;
257         int sock;
258         unsigned int ref_count;
259 };
260
261
262 /* The marshaller for the protocol version 2. */
263 static char *smb_traffic_analyzer_create_string( struct tm *tm, \
264         int seconds, vfs_handle_struct *handle, \
265         char *username, int vfs_operation, int count, ... )
266 {
267         
268         va_list ap;
269         char *arg = NULL;
270         int len;
271         char *header = NULL;
272         char *buf = NULL;
273         char *timestr = NULL;
274         char *opstr = NULL;
275         char *sidstr = NULL;
276         char *userstr = NULL;
277         char *usersid = NULL;
278         const char *total_anonymization = NULL;
279         const char *anon_prefix = NULL;
280
281         /* first create the data that is transfered with any VFS op */
282         opstr = talloc_asprintf(talloc_tos(), "%i", vfs_operation);
283         len = strlen(opstr);
284         buf = talloc_asprintf(talloc_tos(), "%04u%s", len, opstr);
285         len = strlen( username );
286         buf = talloc_asprintf_append(buf, "%04u%s", len, username);
287
288         /*
289          * Handle anonymization. In protocol v2, we have to anonymize
290          * both the SID and the username.
291          */
292         total_anonymization=lp_parm_const_string(SNUM(handle->conn),
293                                         "smb_traffic_analyzer",
294                                         "total_anonymization", NULL);
295
296         anon_prefix=lp_parm_const_string(SNUM(handle->conn),
297                                         "smb_traffic_analyzer",
298                                         "anonymize_prefix", NULL );
299         usersid = dom_sid_string(talloc_tos(),
300                 &handle->conn->server_info->ptok->user_sids[0]);
301         if (anon_prefix != NULL) {
302                 if (total_anonymization != NULL) {
303                         userstr = talloc_asprintf(talloc_tos(), "%s",
304                                                         anon_prefix);                   
305                         sidstr = talloc_asprintf(talloc_tos(), "%s",
306                                                         anon_prefix);
307                 } else {
308                         userstr = talloc_asprintf(talloc_tos(), "%s%i",
309                                 anon_prefix,
310                                 str_checksum(username));
311                         sidstr = talloc_asprintf(talloc_tos(), "%s%i",
312                                 anon_prefix,
313                                 str_checksum(usersid));
314                 }
315         } else {
316                 userstr = username;
317                 sidstr = usersid;
318         }
319
320         len = strlen( userstr );
321         buf = talloc_asprintf_append(buf, "%04u%s", len, userstr);
322         len = strlen( sidstr );
323         buf = talloc_asprintf_append(buf, "%04u%s", len, sidstr);
324         len = strlen( handle->conn->connectpath );
325         buf = talloc_asprintf_append( buf, "%04u%s", len, \
326                 handle->conn->connectpath );
327         len = strlen( pdb_get_domain(handle->conn->server_info->sam_account) );
328         buf = talloc_asprintf_append( buf, "%04u%s", len, \
329                 pdb_get_domain(handle->conn->server_info->sam_account) );
330         timestr = talloc_asprintf(talloc_tos(), \
331                 "%04d-%02d-%02d %02d:%02d:%02d.%03d", \
332                 tm->tm_year+1900, \
333                 tm->tm_mon+1, \
334                 tm->tm_mday, \
335                 tm->tm_hour, \
336                 tm->tm_min, \
337                 tm->tm_sec, \
338                 (int)seconds);
339         len = strlen( timestr );
340         buf = talloc_asprintf_append( buf, "%04u%s", len, timestr);
341         
342         va_start( ap, count );
343         while ( count-- ) {
344                 arg = va_arg( ap, char * );
345                 /*
346                  *  protocol v2 sends a four byte string
347                  * as a header to each block, including
348                  * the numbers of bytes to come in the
349                  * next string.
350                  */
351                 len = strlen( arg );
352                 buf = talloc_asprintf_append( buf, "%04u%s", len, arg);
353         }
354         va_end( ap );
355         return buf;
356 }
357
358 static void smb_traffic_analyzer_send_data(vfs_handle_struct *handle,
359                                         void *data,
360                                         enum vfs_id vfs_operation )
361 {
362         struct refcounted_sock *rf_sock = NULL;
363         struct timeval tv;
364         time_t tv_sec;
365         struct tm *tm = NULL;
366         int seconds;
367         char *str = NULL;
368         char *username = NULL;
369         char *header = NULL;
370         const char *anon_prefix = NULL;
371         const char *total_anonymization = NULL;
372         const char *protocol_version = NULL;
373         bool Write = false;
374         size_t len;
375         char state_flags[9] = "000000\0";
376
377         SMB_VFS_HANDLE_GET_DATA(handle, rf_sock, struct refcounted_sock, return);
378
379         if (rf_sock == NULL || rf_sock->sock == -1) {
380                 DEBUG(1, ("smb_traffic_analyzer_send_data: socket is "
381                         "closed\n"));
382                 return;
383         }
384
385         GetTimeOfDay(&tv);
386         tv_sec = convert_timespec_to_time_t(convert_timeval_to_timespec(tv));
387         tm = localtime(&tv_sec);
388         if (!tm) {
389                 return;
390         }
391         seconds=(float) (tv.tv_usec / 1000);
392
393         /*
394          * Check if anonymization is required, and if yes do this only if
395          * we run on protocol version 1. Anonynization for protocol v2 is
396          * handled in it's marshaller function.
397          */
398         total_anonymization=lp_parm_const_string(SNUM(handle->conn),"smb_traffic_analyzer",
399                                         "total_anonymization", NULL);
400
401         anon_prefix=lp_parm_const_string(SNUM(handle->conn),"smb_traffic_analyzer",\
402                                         "anonymize_prefix", NULL );
403
404         protocol_version = lp_parm_const_string(SNUM(handle->conn),
405                                         "smb_traffic_analyzer",
406                                         "protocol_version", NULL );
407
408         if (anon_prefix!=NULL && strcmp(protocol_version,"V2") != 0) {
409                 if (total_anonymization!=NULL) {
410                         username = talloc_asprintf(talloc_tos(),
411                                 "%s",
412                                 anon_prefix);
413                 } else {
414                         username = talloc_asprintf(talloc_tos(),
415                                 "%s%i",
416                                 anon_prefix,
417                                 str_checksum(
418                                         handle->conn->server_info->sanitized_username ) ); 
419                 }
420
421         } else {
422                 username = handle->conn->server_info->sanitized_username;
423         }
424
425         if (!username) {
426                 return;
427         }
428
429         if ( protocol_version == NULL || strcmp( protocol_version,"V1") == 0) {
430
431                 struct rw_data *s_data = (struct rw_data *) data;
432
433                 /*
434                  * in case of protocol v1, ignore any vfs operations
435                  * except read,pread,write,pwrite, and set the "Write"
436                  * bool accordingly, send data and return.
437                  */
438                 if ( vfs_operation > vfs_id_pwrite ) return;
439
440                 if ( vfs_operation <= vfs_id_pread ) Write=false;
441                         else Write=true;
442
443                 str = talloc_asprintf(talloc_tos(),
444                         "V1,%u,\"%s\",\"%s\",\"%c\",\"%s\",\"%s\","
445                         "\"%04d-%02d-%02d %02d:%02d:%02d.%03d\"\n",
446                         (unsigned int) s_data->len,
447                         username,
448                         pdb_get_domain(handle->conn->server_info->sam_account),
449                         Write ? 'W' : 'R',
450                         handle->conn->connectpath,
451                         s_data->filename,
452                         tm->tm_year+1900,
453                         tm->tm_mon+1,
454                         tm->tm_mday,
455                         tm->tm_hour,
456                         tm->tm_min,
457                         tm->tm_sec,
458                         (int)seconds);
459                 if (write_data(rf_sock->sock, str, len) != len) {
460                         DEBUG(1, ("smb_traffic_analyzer_send_data_socket: "
461                         "error sending V1 protocol data to socket!\n"));
462                 return;
463                 }
464
465         } else if ( strcmp( protocol_version, "V2") == 0) {
466
467                 switch( vfs_operation ) {
468                 case vfs_id_mkdir: ;
469                         str = smb_traffic_analyzer_create_string( tm, \
470                                 seconds, handle, username, vfs_id_mkdir, 3,\
471                                 ((struct mkdir_data *) data)->path, \
472                                 talloc_asprintf( talloc_tos(), "%u", \
473                                 ((struct mkdir_data *) data)->mode), \
474                                 talloc_asprintf( talloc_tos(), "%u", \
475                                 ((struct mkdir_data *) data)->result ));
476                         break;
477                 case vfs_id_rmdir: ;
478                         str = smb_traffic_analyzer_create_string( tm, \
479                                 seconds, handle, username, vfs_id_rmdir, 2,\
480                                 ((struct rmdir_data *) data)->path, \
481                                 talloc_asprintf( talloc_tos(), "%u", \
482                                 ((struct rmdir_data *) data)->result ));
483                         break;
484                 case vfs_id_rename: ;
485                         str = smb_traffic_analyzer_create_string( tm, \
486                                 seconds, handle, username, vfs_id_rename, 3,\
487                                 ((struct rename_data *) data)->src, \
488                                 ((struct rename_data *) data)->dst,
489                                 talloc_asprintf(talloc_tos(), "%u", \
490                                 ((struct rename_data *) data)->result));
491                         break;
492                 case vfs_id_chdir: ;
493                         str = smb_traffic_analyzer_create_string( tm, \
494                                 seconds, handle, username, vfs_id_chdir, 2,\
495                                 ((struct chdir_data *) data)->path, \
496                                 talloc_asprintf(talloc_tos(), "%u", \
497                                 ((struct chdir_data *) data)->result));
498                         break;
499
500                 case vfs_id_write:
501                 case vfs_id_pwrite:
502                 case vfs_id_read:
503                 case vfs_id_pread: ;
504                         str = smb_traffic_analyzer_create_string( tm, \
505                                 seconds, handle, username, vfs_operation, 2,\
506                                 ((struct rw_data *) data)->filename, \
507                                 talloc_asprintf(talloc_tos(), "%u", \
508                                 ((struct rw_data *) data)->len));
509                         break;
510                 default:
511                         DEBUG(1, ("smb_traffic_analyzer: error! "
512                                 "wrong VFS operation id detected!\n"));
513                         return;
514                 }
515
516         } else {
517                 DEBUG(1, ("smb_traffic_analyzer_send_data_socket: "
518                         "error, unkown protocol given!\n"));
519                 return;
520         }
521
522         if (!str) {
523                 DEBUG(1, ("smb_traffic_analyzer_send_data: "
524                         "unable to create string to send!\n"));
525                 return;
526         }
527
528
529         /*
530          * If configured, optain the key and run AES encryption
531          * over the data.
532          */
533         size_t size;
534         char *akey = secrets_fetch("smb_traffic_analyzer_key", &size);
535         if ( akey != NULL ) {
536                 char *crypted;
537                 state_flags[2] = 'E';
538                 DEBUG(10, ("smb_traffic_analyzer: a key was found, encrypting "
539                         "data!"));
540                 AES_KEY *key;
541                 samba_AES_set_encrypt_key(akey, 128, key);
542                 samba_AES_encrypt( str, crypted, key );
543                 len = strlen( crypted );
544                 header = talloc_asprintf( talloc_tos(), "V2.%s%017u",
545                                                 state_flags, len);
546
547                 DEBUG(10, ("smb_traffic_analyzer_send_data_socket:"
548                         " header created for crypted data: %s", header));
549                 len = strlen(header);
550                 if (write_data(rf_sock->sock, header, len) != len) {
551                         DEBUG(1, ("smb_traffic_analyzer_send_data_socket: "
552                                                 "error sending the header"
553                                                  " over the socket!\n"));
554                 }
555                 len = strlen(crypted);
556                 if (write_data(rf_sock->sock, crypted, len) != len) {
557                         DEBUG(1, ("smb_traffic_analyzer_send_data_socket: "
558                                 "error sending crypted data to socket!\n"));
559                 free( crypted );
560                 return ;
561                 }
562         }
563
564         len = strlen(str);
565         header = talloc_asprintf(talloc_tos(), "V2.%s%017u", state_flags, len);
566         DEBUG(10, ("smb_traffic_analyzer_send_data_socket: header created:"
567                                                         "%s\n", header));
568         len = strlen(header);
569         if (write_data(rf_sock->sock, header, len) != len) {
570                 DEBUG(1, ("smb_traffic_analyzer_send_data_socket: error "
571                         "sending the header over the socket!\n"));
572         }
573         len = strlen(str);
574         DEBUG(10, ("smb_traffic_analyzer_send_data_socket: going to send "
575                         "data block: %s\n",str));
576         if (write_data(rf_sock->sock, str, len) != len) {
577                 DEBUG(1, ("smb_traffic_analyzer_send_data_socket: "
578                         "error sending data to socket!\n"));
579                 return ;
580         }
581 }
582
583 static struct refcounted_sock *sock_list;
584
585 static void smb_traffic_analyzer_free_data(void **pptr)
586 {
587         struct refcounted_sock *rf_sock = *(struct refcounted_sock **)pptr;
588         if (rf_sock == NULL) {
589                 return;
590         }
591         rf_sock->ref_count--;
592         if (rf_sock->ref_count != 0) {
593                 return;
594         }
595         if (rf_sock->sock != -1) {
596                 close(rf_sock->sock);
597         }
598         DLIST_REMOVE(sock_list, rf_sock);
599         TALLOC_FREE(rf_sock);
600 }
601
602 static int smb_traffic_analyzer_connect(struct vfs_handle_struct *handle,
603                          const char *service,
604                          const char *user)
605 {
606         connection_struct *conn = handle->conn;
607         enum sock_type st = smb_traffic_analyzer_connMode(handle);
608         struct refcounted_sock *rf_sock = NULL;
609         const char *name = (st == UNIX_DOMAIN_SOCKET) ? LOCAL_PATHNAME :
610                                 lp_parm_const_string(SNUM(conn),
611                                         "smb_traffic_analyzer",
612                                 "host", "localhost");
613         uint16_t port = (st == UNIX_DOMAIN_SOCKET) ? 0 :
614                                 atoi( lp_parm_const_string(SNUM(conn),
615                                 "smb_traffic_analyzer", "port", "9430"));
616         int ret = SMB_VFS_NEXT_CONNECT(handle, service, user);
617
618         if (ret < 0) {
619                 return ret;
620         }
621
622         /* Are we already connected ? */
623         for (rf_sock = sock_list; rf_sock; rf_sock = rf_sock->next) {
624                 if (port == rf_sock->port &&
625                                 (strcmp(name, rf_sock->name) == 0)) {
626                         break;
627                 }
628         }
629
630         /* If we're connected already, just increase the
631          * reference count. */
632         if (rf_sock) {
633                 rf_sock->ref_count++;
634         } else {
635                 /* New connection. */
636                 rf_sock = TALLOC_ZERO_P(NULL, struct refcounted_sock);
637                 if (rf_sock == NULL) {
638                         SMB_VFS_NEXT_DISCONNECT(handle);
639                         errno = ENOMEM;
640                         return -1;
641                 }
642                 rf_sock->name = talloc_strdup(rf_sock, name);
643                 if (rf_sock->name == NULL) {
644                         SMB_VFS_NEXT_DISCONNECT(handle);
645                         TALLOC_FREE(rf_sock);
646                         errno = ENOMEM;
647                         return -1;
648                 }
649                 rf_sock->port = port;
650                 rf_sock->ref_count = 1;
651
652                 if (st == UNIX_DOMAIN_SOCKET) {
653                         rf_sock->sock = smb_traffic_analyzer_connect_unix_socket(handle,
654                                                         name);
655                 } else {
656
657                         rf_sock->sock = smb_traffic_analyzer_connect_inet_socket(handle,
658                                                         name,
659                                                         port);
660                 }
661                 if (rf_sock->sock == -1) {
662                         SMB_VFS_NEXT_DISCONNECT(handle);
663                         TALLOC_FREE(rf_sock);
664                         return -1;
665                 }
666                 DLIST_ADD(sock_list, rf_sock);
667         }
668
669         /* Store the private data. */
670         SMB_VFS_HANDLE_SET_DATA(handle, rf_sock, smb_traffic_analyzer_free_data,
671                                 struct refcounted_sock, return -1);
672         return 0;
673 }
674
675 /* VFS Functions */
676 static int smb_traffic_analyzer_chdir(vfs_handle_struct *handle, \
677                         const char *path)
678 {
679         struct chdir_data s_data;
680         s_data.result = SMB_VFS_NEXT_CHDIR(handle, path);
681         s_data.path = path;
682         DEBUG(10, ("smb_traffic_analyzer_chdir: CHDIR: %s\n", path));
683         smb_traffic_analyzer_send_data(handle, &s_data, vfs_id_chdir);
684         return s_data.result;
685 }
686
687 static int smb_traffic_analyzer_rename(vfs_handle_struct *handle, \
688                 const struct smb_filename *smb_fname_src,
689                 const struct smb_filename *smb_fname_dst)
690 {
691         struct rename_data s_data;
692         s_data.result = SMB_VFS_NEXT_RENAME(handle, smb_fname_src, \
693                 smb_fname_dst);
694         s_data.src = smb_fname_src->base_name;
695         s_data.dst = smb_fname_dst->base_name;
696         DEBUG(10, ("smb_traffic_analyzer_rename: RENAME: %s / %s\n",
697                 smb_fname_src->base_name,
698                 smb_fname_dst->base_name));
699         smb_traffic_analyzer_send_data(handle, &s_data, vfs_id_rename);
700         return s_data.result;
701 }
702
703 static int smb_traffic_analyzer_rmdir(vfs_handle_struct *handle, \
704                         const char *path)
705 {
706         struct rmdir_data s_data;
707         s_data.result = SMB_VFS_NEXT_RMDIR(handle, path);
708         s_data.path = path;
709         DEBUG(10, ("smb_traffic_analyzer_rmdir: RMDIR: %s\n", path));
710         smb_traffic_analyzer_send_data(handle, &s_data, vfs_id_rmdir);
711         return s_data.result;
712 }
713
714 static int smb_traffic_analyzer_mkdir(vfs_handle_struct *handle, \
715                         const char *path, mode_t mode)
716 {
717         struct mkdir_data s_data;
718         s_data.result = SMB_VFS_NEXT_MKDIR(handle, path, mode);
719         s_data.path = path;
720         s_data.mode = mode;
721         DEBUG(10, ("smb_traffic_analyzer_mkdir: MKDIR: %s\n", path));
722         smb_traffic_analyzer_send_data(handle,
723                         &s_data,
724                         vfs_id_mkdir);
725         return s_data.result;
726 }
727
728 static ssize_t smb_traffic_analyzer_read(vfs_handle_struct *handle, \
729                                 files_struct *fsp, void *data, size_t n)
730 {
731         struct rw_data s_data;
732
733         s_data.len = SMB_VFS_NEXT_READ(handle, fsp, data, n);
734         s_data.filename = fsp->fsp_name->base_name;
735         DEBUG(10, ("smb_traffic_analyzer_read: READ: %s\n", fsp_str_dbg(fsp)));
736
737         smb_traffic_analyzer_send_data(handle,
738                         &s_data,
739                         vfs_id_read);
740         return s_data.len;
741 }
742
743
744 static ssize_t smb_traffic_analyzer_pread(vfs_handle_struct *handle, \
745                 files_struct *fsp, void *data, size_t n, SMB_OFF_T offset)
746 {
747         struct rw_data s_data;
748
749         s_data.len = SMB_VFS_NEXT_PREAD(handle, fsp, data, n, offset);
750         s_data.filename = fsp->fsp_name->base_name;
751         DEBUG(10, ("smb_traffic_analyzer_pread: PREAD: %s\n",
752                    fsp_str_dbg(fsp)));
753
754         smb_traffic_analyzer_send_data(handle,
755                         &s_data,
756                         vfs_id_pread);
757
758         return s_data.len;
759 }
760
761 static ssize_t smb_traffic_analyzer_write(vfs_handle_struct *handle, \
762                         files_struct *fsp, const void *data, size_t n)
763 {
764         struct rw_data s_data;
765
766         s_data.len = SMB_VFS_NEXT_WRITE(handle, fsp, data, n);
767         s_data.filename = fsp->fsp_name->base_name;
768         DEBUG(10, ("smb_traffic_analyzer_write: WRITE: %s\n",
769                    fsp_str_dbg(fsp)));
770
771         smb_traffic_analyzer_send_data(handle,
772                         &s_data,
773                         vfs_id_write);
774         return s_data.len;
775 }
776
777 static ssize_t smb_traffic_analyzer_pwrite(vfs_handle_struct *handle, \
778              files_struct *fsp, const void *data, size_t n, SMB_OFF_T offset)
779 {
780         struct rw_data s_data;
781
782         s_data.len = SMB_VFS_NEXT_PWRITE(handle, fsp, data, n, offset);
783         s_data.filename = fsp->fsp_name->base_name;
784         DEBUG(10, ("smb_traffic_analyzer_pwrite: PWRITE: %s\n", \
785                 fsp_str_dbg(fsp)));
786
787         smb_traffic_analyzer_send_data(handle,
788                         &s_data,
789                         vfs_id_pwrite);
790         return s_data.len;
791 }
792
793 static struct vfs_fn_pointers vfs_smb_traffic_analyzer_fns = {
794         .connect_fn = smb_traffic_analyzer_connect,
795         .vfs_read = smb_traffic_analyzer_read,
796         .pread = smb_traffic_analyzer_pread,
797         .write = smb_traffic_analyzer_write,
798         .pwrite = smb_traffic_analyzer_pwrite,
799         .mkdir = smb_traffic_analyzer_mkdir,
800         .rename = smb_traffic_analyzer_rename,
801         .chdir = smb_traffic_analyzer_chdir
802 };
803
804 /* Module initialization */
805 NTSTATUS vfs_smb_traffic_analyzer_init(void)
806 {
807         NTSTATUS ret = smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
808                                         "smb_traffic_analyzer",
809                                         &vfs_smb_traffic_analyzer_fns);
810
811         if (!NT_STATUS_IS_OK(ret)) {
812                 return ret;
813         }
814
815         vfs_smb_traffic_analyzer_debug_level =
816                 debug_add_class("smb_traffic_analyzer");
817
818         if (vfs_smb_traffic_analyzer_debug_level == -1) {
819                 vfs_smb_traffic_analyzer_debug_level = DBGC_VFS;
820                 DEBUG(1, ("smb_traffic_analyzer_init: Couldn't register custom"
821                          "debugging class!\n"));
822         } else {
823                 DEBUG(3, ("smb_traffic_analyzer_init: Debug class number of"
824                         "'smb_traffic_analyzer': %d\n", \
825                         vfs_smb_traffic_analyzer_debug_level));
826         }
827
828         return ret;
829 }