s3-vfs: include smbd/smbd.h in vfs modules.
[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-2010
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 "smbd/smbd.h"
24 #include "../smbd/globals.h"
25 #include "../lib/crypto/crypto.h"
26 #include "vfs_smb_traffic_analyzer.h"
27 #include "../libcli/security/security.h"
28 #include "secrets.h"
29 #include "../librpc/gen_ndr/ndr_netlogon.h"
30
31 /* abstraction for the send_over_network function */
32 enum sock_type {INTERNET_SOCKET = 0, UNIX_DOMAIN_SOCKET};
33
34 #define LOCAL_PATHNAME "/var/tmp/stadsocket"
35
36 static int vfs_smb_traffic_analyzer_debug_level = DBGC_VFS;
37
38 static enum sock_type smb_traffic_analyzer_connMode(vfs_handle_struct *handle)
39 {
40         connection_struct *conn = handle->conn;
41         const char *Mode;
42         Mode=lp_parm_const_string(SNUM(conn), "smb_traffic_analyzer","mode", \
43                         "internet_socket");
44         if (strstr(Mode,"unix_domain_socket")) {
45                 return UNIX_DOMAIN_SOCKET;
46         } else {
47                 return INTERNET_SOCKET;
48         }
49 }
50
51
52 /* Connect to an internet socket */
53 static int smb_traffic_analyzer_connect_inet_socket(vfs_handle_struct *handle,
54                                         const char *name, uint16_t port)
55 {
56         /* Create a streaming Socket */
57         int sockfd = -1;
58         struct addrinfo hints;
59         struct addrinfo *ailist = NULL;
60         struct addrinfo *res = NULL;
61         int ret;
62
63         ZERO_STRUCT(hints);
64         /* By default make sure it supports TCP. */
65         hints.ai_socktype = SOCK_STREAM;
66         hints.ai_flags = AI_ADDRCONFIG;
67
68         ret = getaddrinfo(name,
69                         NULL,
70                         &hints,
71                         &ailist);
72
73         if (ret) {
74                 DEBUG(3,("smb_traffic_analyzer_connect_inet_socket: "
75                         "getaddrinfo failed for name %s [%s]\n",
76                         name,
77                         gai_strerror(ret) ));
78                 return -1;
79         }
80
81         DEBUG(3,("smb_traffic_analyzer: Internet socket mode. Hostname: %s,"
82                 "Port: %i\n", name, port));
83
84         for (res = ailist; res; res = res->ai_next) {
85                 struct sockaddr_storage ss;
86                 NTSTATUS status;
87
88                 if (!res->ai_addr || res->ai_addrlen == 0) {
89                         continue;
90                 }
91
92                 ZERO_STRUCT(ss);
93                 memcpy(&ss, res->ai_addr, res->ai_addrlen);
94
95                 status = open_socket_out(&ss, port, 10000, &sockfd);
96                 if (NT_STATUS_IS_OK(status)) {
97                         break;
98                 }
99         }
100
101         if (ailist) {
102                 freeaddrinfo(ailist);
103         }
104
105         if (sockfd == -1) {
106                 DEBUG(1, ("smb_traffic_analyzer: unable to create "
107                         "socket, error is %s",
108                         strerror(errno)));
109                 return -1;
110         }
111
112         return sockfd;
113 }
114
115 /* Connect to a unix domain socket */
116 static int smb_traffic_analyzer_connect_unix_socket(vfs_handle_struct *handle,
117                                                 const char *name)
118 {
119         /* Create the socket to stad */
120         int len, sock;
121         struct sockaddr_un remote;
122
123         DEBUG(7, ("smb_traffic_analyzer_connect_unix_socket: "
124                         "Unix domain socket mode. Using %s\n",
125                         name ));
126
127         if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
128                 DEBUG(1, ("smb_traffic_analyzer_connect_unix_socket: "
129                         "Couldn't create socket, "
130                         "make sure stad is running!\n"));
131                 return -1;
132         }
133         remote.sun_family = AF_UNIX;
134         strlcpy(remote.sun_path, name,
135                     sizeof(remote.sun_path));
136         len=strlen(remote.sun_path) + sizeof(remote.sun_family);
137         if (connect(sock, (struct sockaddr *)&remote, len) == -1 ) {
138                 DEBUG(1, ("smb_traffic_analyzer_connect_unix_socket: "
139                         "Could not connect to "
140                         "socket, make sure\nstad is running!\n"));
141                 close(sock);
142                 return -1;
143         }
144         return sock;
145 }
146
147 /* Private data allowing shared connection sockets. */
148 struct refcounted_sock {
149         struct refcounted_sock *next, *prev;
150         char *name;
151         uint16_t port;
152         int sock;
153         unsigned int ref_count;
154 };
155
156
157 /**
158  * Encryption of a data block with AES
159  * TALLOC_CTX *ctx      Talloc context to work on
160  * const char *akey     128bit key for the encryption
161  * const char *str      Data buffer to encrypt, \0 terminated
162  * int *len             Will be set to the length of the
163  *                      resulting data block
164  * The caller has to take care for the memory
165  * allocated on the context.
166  */
167 static char *smb_traffic_analyzer_encrypt( TALLOC_CTX *ctx,
168         const char *akey, const char *str, size_t *len)
169 {
170         int s1,s2,h,d;
171         AES_KEY key;
172         unsigned char filler[17]= "................";
173         char *output;
174         unsigned char crypted[18];
175         if (akey == NULL) return NULL;
176         samba_AES_set_encrypt_key((unsigned char *) akey, 128, &key);
177         s1 = strlen(str) / 16;
178         s2 = strlen(str) % 16;
179         for (h = 0; h < s2; h++) *(filler+h)=*(str+(s1*16)+h);
180         DEBUG(10, ("smb_traffic_analyzer_send_data_socket: created %s"
181                 " as filling block.\n", filler));
182         output = talloc_array(ctx, char, (s1*16)+17 );
183         d=0;
184         for (h = 0; h < s1; h++) {
185                 samba_AES_encrypt((unsigned char *) str+(16*h), crypted, &key);
186                 for (d = 0; d<16; d++) output[d+(16*h)]=crypted[d];
187         }
188         samba_AES_encrypt( (unsigned char *) str+(16*h), filler, &key );
189         for (d = 0;d < 16; d++) output[d+(16*h)]=*(filler+d);
190         *len = (s1*16)+16;
191         return output;  
192 }
193
194 /**
195  * Create a v2 header.
196  * TALLLOC_CTX *ctx             Talloc context to work on
197  * const char *state_flags      State flag string
198  * int len                      length of the data block
199  */
200 static char *smb_traffic_analyzer_create_header( TALLOC_CTX *ctx,
201         const char *state_flags, size_t data_len)
202 {
203         char *header = talloc_asprintf( ctx, "V2.%s%017u",
204                                         state_flags, (unsigned int) data_len);
205         DEBUG(10, ("smb_traffic_analyzer_send_data_socket: created Header:\n"));
206         dump_data(10, (uint8_t *)header, strlen(header));
207         return header;
208 }
209
210
211 /**
212  * Actually send header and data over the network
213  * char *header         Header data
214  * char *data           Data Block
215  * int dlength          Length of data block
216  * int socket
217  */
218 static void smb_traffic_analyzer_write_data( char *header, char *data,
219                         int dlength, int _socket)
220 {
221                 int len = strlen(header);
222                 if (write_data( _socket, header, len) != len) {
223                         DEBUG(1, ("smb_traffic_analyzer_send_data_socket: "
224                                                 "error sending the header"
225                                                 " over the socket!\n"));
226                 }
227                 DEBUG(10,("smb_traffic_analyzer_write_data: sending data:\n"));
228                 dump_data( 10, (uint8_t *)data, dlength);
229
230                 if (write_data( _socket, data, dlength) != dlength) {
231                         DEBUG(1, ("smb_traffic_analyzer_write_data: "
232                                 "error sending crypted data to socket!\n"));
233                 }
234 }
235
236
237 /*
238  * Anonymize a string if required.
239  * TALLOC_CTX *ctx                      The talloc context to work on
240  * const char *str                      The string to anonymize
241  * vfs_handle_struct *handle            The handle struct to work on
242  *
243  * Returns a newly allocated string, either the anonymized one,
244  * or a copy of const char *str. The caller has to take care for
245  * freeing the allocated memory.
246  */
247 static char *smb_traffic_analyzer_anonymize( TALLOC_CTX *ctx,
248                                         const char *str,
249                                         vfs_handle_struct *handle )
250 {
251         const char *total_anonymization;
252         const char *anon_prefix;
253         char *output;
254         total_anonymization=lp_parm_const_string(SNUM(handle->conn),
255                                         "smb_traffic_analyzer",
256                                         "total_anonymization", NULL);
257
258         anon_prefix=lp_parm_const_string(SNUM(handle->conn),
259                                         "smb_traffic_analyzer",
260                                         "anonymize_prefix", NULL );
261         if (anon_prefix != NULL) {
262                 if (total_anonymization != NULL) {
263                         output = talloc_asprintf(ctx, "%s",
264                                         anon_prefix);
265                 } else {
266                 output = talloc_asprintf(ctx, "%s%i", anon_prefix,
267                                                 str_checksum(str));
268                 }
269         } else {
270                 output = talloc_asprintf(ctx, "%s", str);
271         }
272
273         return output;
274 }
275
276
277 /**
278  * The marshalling function for protocol v2.
279  * TALLOC_CTX *ctx              Talloc context to work on
280  * struct tm *tm                tm struct for the timestamp
281  * int seconds                  milliseconds of the timestamp
282  * vfs_handle_struct *handle    vfs_handle_struct
283  * char *username               Name of the user
284  * int vfs_operation            VFS operation identifier
285  * int count                    Number of the common data blocks
286  * [...] variable args          data blocks taken from the individual
287  *                              VFS data structures
288  *
289  * Returns the complete data block to send. The caller has to
290  * take care for freeing the allocated buffer.
291  */
292 static char *smb_traffic_analyzer_create_string( TALLOC_CTX *ctx,
293         struct tm *tm, int seconds, vfs_handle_struct *handle, \
294         char *username, int vfs_operation, int count, ... )
295 {
296         
297         va_list ap;
298         char *arg = NULL;
299         int len;
300         char *common_data_count_str = NULL;
301         char *timestr = NULL;
302         char *sidstr = NULL;
303         char *usersid = NULL;
304         char *buf = NULL;
305         char *vfs_operation_str = NULL;
306         const char *service_name = lp_const_servicename(handle->conn->params->service);
307
308         /*
309          * first create the data that is transfered with any VFS op
310          * These are, in the following order:
311          *(0) number of data to come [6 in v2.0]
312          * 1.vfs_operation identifier
313          * 2.username
314          * 3.user-SID
315          * 4.affected share
316          * 5.domain
317          * 6.timestamp
318          * 7.IP Addresss of client
319          */
320
321         /*
322          * number of common data blocks to come,
323          * this is a #define in vfs_smb_traffic_anaylzer.h,
324          * it's length is known at compile time
325          */
326         common_data_count_str = talloc_strdup( ctx, SMBTA_COMMON_DATA_COUNT);
327         /* vfs operation identifier */
328         vfs_operation_str = talloc_asprintf( common_data_count_str, "%i",
329                                                         vfs_operation);
330         /*
331          * Handle anonymization. In protocol v2, we have to anonymize
332          * both the SID and the username. The name is already
333          * anonymized if needed, by the calling function.
334          */
335         usersid = dom_sid_string( common_data_count_str,
336                 &handle->conn->session_info->security_token->sids[0]);
337
338         sidstr = smb_traffic_analyzer_anonymize(
339                 common_data_count_str,
340                 usersid,
341                 handle);
342         
343         /* time stamp */
344         timestr = talloc_asprintf( common_data_count_str, \
345                 "%04d-%02d-%02d %02d:%02d:%02d.%03d", \
346                 tm->tm_year+1900, \
347                 tm->tm_mon+1, \
348                 tm->tm_mday, \
349                 tm->tm_hour, \
350                 tm->tm_min, \
351                 tm->tm_sec, \
352                 (int)seconds);
353         len = strlen( timestr );
354         /* create the string of common data */
355         buf = talloc_asprintf(ctx,
356                 "%s%04u%s%04u%s%04u%s%04u%s%04u%s%04u%s%04u%s",
357                 common_data_count_str,
358                 (unsigned int) strlen(vfs_operation_str),
359                 vfs_operation_str,
360                 (unsigned int) strlen(username),
361                 username,
362                 (unsigned int) strlen(sidstr),
363                 sidstr,
364                 (unsigned int) strlen(service_name),
365                 service_name,
366                 (unsigned int)
367                 strlen(handle->conn->session_info->info3->base.domain.string),
368                 handle->conn->session_info->info3->base.domain.string,
369                 (unsigned int) strlen(timestr),
370                 timestr,
371                 (unsigned int) strlen(handle->conn->sconn->client_id.addr),
372                 handle->conn->sconn->client_id.addr);
373
374         talloc_free(common_data_count_str);
375
376         /* data blocks depending on the VFS function */ 
377         va_start( ap, count );
378         while ( count-- ) {
379                 arg = va_arg( ap, char * );
380                 /*
381                  *  protocol v2 sends a four byte string
382                  * as a header to each block, including
383                  * the numbers of bytes to come in the
384                  * next string.
385                  */
386                 len = strlen( arg );
387                 buf = talloc_asprintf_append( buf, "%04u%s", len, arg);
388         }
389         va_end( ap );
390         return buf;
391 }
392
393 static void smb_traffic_analyzer_send_data(vfs_handle_struct *handle,
394                                         void *data,
395                                         enum vfs_id vfs_operation )
396 {
397         struct refcounted_sock *rf_sock = NULL;
398         struct timeval tv;
399         time_t tv_sec;
400         struct tm *tm = NULL;
401         int seconds;
402         char *str = NULL;
403         char *username = NULL;
404         char *header = NULL;
405         const char *protocol_version = NULL;
406         bool Write = false;
407         size_t len;
408         size_t size;
409         char *akey, *output;
410
411         /*
412          * The state flags are part of the header
413          * and are descripted in the protocol description
414          * in vfs_smb_traffic_analyzer.h. They begin at byte
415          * 03 of the header.
416          */
417         char state_flags[9] = "000000\0";
418
419         SMB_VFS_HANDLE_GET_DATA(handle, rf_sock, struct refcounted_sock, return);
420
421         if (rf_sock == NULL || rf_sock->sock == -1) {
422                 DEBUG(1, ("smb_traffic_analyzer_send_data: socket is "
423                         "closed\n"));
424                 return;
425         }
426
427         GetTimeOfDay(&tv);
428         tv_sec = tv.tv_sec;
429         tm = localtime(&tv_sec);
430         if (!tm) {
431                 return;
432         }
433         seconds=(float) (tv.tv_usec / 1000);
434
435         /*
436          * Check if anonymization is required, and if yes do this only for
437          * the username here, needed vor protocol version 1. In v2 we
438          * additionally anonymize the SID, which is done in it's marshalling
439          * function.
440          */
441         username = smb_traffic_analyzer_anonymize( talloc_tos(),
442                         handle->conn->session_info->sanitized_username,
443                         handle);
444
445         if (!username) {
446                 return;
447         }
448
449         protocol_version = lp_parm_const_string(SNUM(handle->conn),
450                                         "smb_traffic_analyzer",
451                                         "protocol_version", NULL );
452
453
454         if ( protocol_version == NULL || strcmp( protocol_version,"V1") == 0) {
455
456                 struct rw_data *s_data = (struct rw_data *) data;
457
458                 /*
459                  * in case of protocol v1, ignore any vfs operations
460                  * except read,pread,write,pwrite, and set the "Write"
461                  * bool accordingly, send data and return.
462                  */
463                 if ( vfs_operation > vfs_id_pwrite ) return;
464
465                 if ( vfs_operation <= vfs_id_pread ) Write=false;
466                         else Write=true;
467
468                 str = talloc_asprintf(talloc_tos(),
469                         "V1,%u,\"%s\",\"%s\",\"%c\",\"%s\",\"%s\","
470                         "\"%04d-%02d-%02d %02d:%02d:%02d.%03d\"\n",
471                         (unsigned int) s_data->len,
472                         username,
473                         handle->conn->session_info->info3->base.domain.string,
474                         Write ? 'W' : 'R',
475                         handle->conn->connectpath,
476                         s_data->filename,
477                         tm->tm_year+1900,
478                         tm->tm_mon+1,
479                         tm->tm_mday,
480                         tm->tm_hour,
481                         tm->tm_min,
482                         tm->tm_sec,
483                         (int)seconds);
484                 len = strlen(str);
485                 if (write_data(rf_sock->sock, str, len) != len) {
486                         DEBUG(1, ("smb_traffic_analyzer_send_data_socket: "
487                         "error sending V1 protocol data to socket!\n"));
488                 return;
489                 }
490
491         } else if ( strcmp( protocol_version, "V2") == 0) {
492
493                 switch( vfs_operation ) {
494                 case vfs_id_open: ;
495                         str = smb_traffic_analyzer_create_string( talloc_tos(),
496                                 tm, seconds, handle, username, vfs_id_open,
497                                 3, ((struct open_data *) data)->filename,
498                                 talloc_asprintf( talloc_tos(), "%u",
499                                 ((struct open_data *) data)->mode),
500                                 talloc_asprintf( talloc_tos(), "%u",
501                                 ((struct open_data *) data)->result));
502                         break;
503                 case vfs_id_close: ;
504                         str = smb_traffic_analyzer_create_string( talloc_tos(),
505                                 tm, seconds, handle, username, vfs_id_close,
506                                 2, ((struct close_data *) data)->filename,
507                                 talloc_asprintf( talloc_tos(), "%u",
508                                 ((struct close_data *) data)->result));
509                         break;
510                 case vfs_id_mkdir: ;
511                         str = smb_traffic_analyzer_create_string( talloc_tos(),
512                                 tm, seconds, handle, username, vfs_id_mkdir, \
513                                 3, ((struct mkdir_data *) data)->path, \
514                                 talloc_asprintf( talloc_tos(), "%u", \
515                                 ((struct mkdir_data *) data)->mode), \
516                                 talloc_asprintf( talloc_tos(), "%u", \
517                                 ((struct mkdir_data *) data)->result ));
518                         break;
519                 case vfs_id_rmdir: ;
520                         str = smb_traffic_analyzer_create_string( talloc_tos(),
521                                 tm, seconds, handle, username, vfs_id_rmdir,
522                                 2, ((struct rmdir_data *) data)->path, \
523                                 talloc_asprintf( talloc_tos(), "%u", \
524                                 ((struct rmdir_data *) data)->result ));
525                         break;
526                 case vfs_id_rename: ;
527                         str = smb_traffic_analyzer_create_string( talloc_tos(),
528                                 tm, seconds, handle, username, vfs_id_rename,
529                                 3, ((struct rename_data *) data)->src, \
530                                 ((struct rename_data *) data)->dst,
531                                 talloc_asprintf(talloc_tos(), "%u", \
532                                 ((struct rename_data *) data)->result));
533                         break;
534                 case vfs_id_chdir: ;
535                         str = smb_traffic_analyzer_create_string( talloc_tos(),
536                                 tm, seconds, handle, username, vfs_id_chdir,
537                                 2, ((struct chdir_data *) data)->path, \
538                                 talloc_asprintf(talloc_tos(), "%u", \
539                                 ((struct chdir_data *) data)->result));
540                         break;
541
542                 case vfs_id_write:
543                 case vfs_id_pwrite:
544                 case vfs_id_read:
545                 case vfs_id_pread: ;
546                         str = smb_traffic_analyzer_create_string( talloc_tos(),
547                                 tm, seconds, handle, username, vfs_operation,
548                                 2, ((struct rw_data *) data)->filename, \
549                                 talloc_asprintf(talloc_tos(), "%u", \
550                                 (unsigned int)
551                                         ((struct rw_data *) data)->len));
552                         break;
553                 default:
554                         DEBUG(1, ("smb_traffic_analyzer: error! "
555                                 "wrong VFS operation id detected!\n"));
556                         return;
557                 }
558
559         } else {
560                 DEBUG(1, ("smb_traffic_analyzer_send_data_socket: "
561                         "error, unknown protocol given!\n"));
562                 return;
563         }
564
565         if (!str) {
566                 DEBUG(1, ("smb_traffic_analyzer_send_data: "
567                         "unable to create string to send!\n"));
568                 return;
569         }
570
571
572         /*
573          * If configured, optain the key and run AES encryption
574          * over the data.
575          */
576         become_root();
577         akey = (char *) secrets_fetch("smb_traffic_analyzer_key", &size);
578         unbecome_root();
579         if ( akey != NULL ) {
580                 state_flags[2] = 'E';
581                 DEBUG(10, ("smb_traffic_analyzer_send_data_socket: a key was"
582                         " found, encrypting data!\n"));
583                 output = smb_traffic_analyzer_encrypt( talloc_tos(),
584                                                 akey, str, &len);
585                 SAFE_FREE(akey);
586                 header = smb_traffic_analyzer_create_header( talloc_tos(),
587                                                 state_flags, len);
588
589                 DEBUG(10, ("smb_traffic_analyzer_send_data_socket:"
590                         " header created for crypted data: %s\n", header));
591                 smb_traffic_analyzer_write_data(header, output, len,
592                                                         rf_sock->sock);
593                 return;
594
595         }
596
597         len = strlen(str);
598         header = smb_traffic_analyzer_create_header( talloc_tos(),
599                                 state_flags, len);
600         smb_traffic_analyzer_write_data(header, str, strlen(str),
601                                 rf_sock->sock);
602
603 }
604
605 static struct refcounted_sock *sock_list;
606
607 static void smb_traffic_analyzer_free_data(void **pptr)
608 {
609         struct refcounted_sock *rf_sock = *(struct refcounted_sock **)pptr;
610         if (rf_sock == NULL) {
611                 return;
612         }
613         rf_sock->ref_count--;
614         if (rf_sock->ref_count != 0) {
615                 return;
616         }
617         if (rf_sock->sock != -1) {
618                 close(rf_sock->sock);
619         }
620         DLIST_REMOVE(sock_list, rf_sock);
621         TALLOC_FREE(rf_sock);
622 }
623
624 static int smb_traffic_analyzer_connect(struct vfs_handle_struct *handle,
625                          const char *service,
626                          const char *user)
627 {
628         connection_struct *conn = handle->conn;
629         enum sock_type st = smb_traffic_analyzer_connMode(handle);
630         struct refcounted_sock *rf_sock = NULL;
631         const char *name = (st == UNIX_DOMAIN_SOCKET) ? LOCAL_PATHNAME :
632                                 lp_parm_const_string(SNUM(conn),
633                                         "smb_traffic_analyzer",
634                                 "host", "localhost");
635         uint16_t port = (st == UNIX_DOMAIN_SOCKET) ? 0 :
636                                 atoi( lp_parm_const_string(SNUM(conn),
637                                 "smb_traffic_analyzer", "port", "9430"));
638         int ret = SMB_VFS_NEXT_CONNECT(handle, service, user);
639
640         if (ret < 0) {
641                 return ret;
642         }
643
644         /* Are we already connected ? */
645         for (rf_sock = sock_list; rf_sock; rf_sock = rf_sock->next) {
646                 if (port == rf_sock->port &&
647                                 (strcmp(name, rf_sock->name) == 0)) {
648                         break;
649                 }
650         }
651
652         /* If we're connected already, just increase the
653          * reference count. */
654         if (rf_sock) {
655                 rf_sock->ref_count++;
656         } else {
657                 /* New connection. */
658                 rf_sock = TALLOC_ZERO_P(NULL, struct refcounted_sock);
659                 if (rf_sock == NULL) {
660                         SMB_VFS_NEXT_DISCONNECT(handle);
661                         errno = ENOMEM;
662                         return -1;
663                 }
664                 rf_sock->name = talloc_strdup(rf_sock, name);
665                 if (rf_sock->name == NULL) {
666                         SMB_VFS_NEXT_DISCONNECT(handle);
667                         TALLOC_FREE(rf_sock);
668                         errno = ENOMEM;
669                         return -1;
670                 }
671                 rf_sock->port = port;
672                 rf_sock->ref_count = 1;
673
674                 if (st == UNIX_DOMAIN_SOCKET) {
675                         rf_sock->sock = smb_traffic_analyzer_connect_unix_socket(handle,
676                                                         name);
677                 } else {
678
679                         rf_sock->sock = smb_traffic_analyzer_connect_inet_socket(handle,
680                                                         name,
681                                                         port);
682                 }
683                 if (rf_sock->sock == -1) {
684                         SMB_VFS_NEXT_DISCONNECT(handle);
685                         TALLOC_FREE(rf_sock);
686                         return -1;
687                 }
688                 DLIST_ADD(sock_list, rf_sock);
689         }
690
691         /* Store the private data. */
692         SMB_VFS_HANDLE_SET_DATA(handle, rf_sock, smb_traffic_analyzer_free_data,
693                                 struct refcounted_sock, return -1);
694         return 0;
695 }
696
697 /* VFS Functions */
698 static int smb_traffic_analyzer_chdir(vfs_handle_struct *handle, \
699                         const char *path)
700 {
701         struct chdir_data s_data;
702         s_data.result = SMB_VFS_NEXT_CHDIR(handle, path);
703         s_data.path = path;
704         DEBUG(10, ("smb_traffic_analyzer_chdir: CHDIR: %s\n", path));
705         smb_traffic_analyzer_send_data(handle, &s_data, vfs_id_chdir);
706         return s_data.result;
707 }
708
709 static int smb_traffic_analyzer_rename(vfs_handle_struct *handle, \
710                 const struct smb_filename *smb_fname_src,
711                 const struct smb_filename *smb_fname_dst)
712 {
713         struct rename_data s_data;
714         s_data.result = SMB_VFS_NEXT_RENAME(handle, smb_fname_src, \
715                 smb_fname_dst);
716         s_data.src = smb_fname_src->base_name;
717         s_data.dst = smb_fname_dst->base_name;
718         DEBUG(10, ("smb_traffic_analyzer_rename: RENAME: %s / %s\n",
719                 smb_fname_src->base_name,
720                 smb_fname_dst->base_name));
721         smb_traffic_analyzer_send_data(handle, &s_data, vfs_id_rename);
722         return s_data.result;
723 }
724
725 static int smb_traffic_analyzer_rmdir(vfs_handle_struct *handle, \
726                         const char *path)
727 {
728         struct rmdir_data s_data;
729         s_data.result = SMB_VFS_NEXT_RMDIR(handle, path);
730         s_data.path = path;
731         DEBUG(10, ("smb_traffic_analyzer_rmdir: RMDIR: %s\n", path));
732         smb_traffic_analyzer_send_data(handle, &s_data, vfs_id_rmdir);
733         return s_data.result;
734 }
735
736 static int smb_traffic_analyzer_mkdir(vfs_handle_struct *handle, \
737                         const char *path, mode_t mode)
738 {
739         struct mkdir_data s_data;
740         s_data.result = SMB_VFS_NEXT_MKDIR(handle, path, mode);
741         s_data.path = path;
742         s_data.mode = mode;
743         DEBUG(10, ("smb_traffic_analyzer_mkdir: MKDIR: %s\n", path));
744         smb_traffic_analyzer_send_data(handle,
745                         &s_data,
746                         vfs_id_mkdir);
747         return s_data.result;
748 }
749
750 static ssize_t smb_traffic_analyzer_read(vfs_handle_struct *handle, \
751                                 files_struct *fsp, void *data, size_t n)
752 {
753         struct rw_data s_data;
754
755         s_data.len = SMB_VFS_NEXT_READ(handle, fsp, data, n);
756         s_data.filename = fsp->fsp_name->base_name;
757         DEBUG(10, ("smb_traffic_analyzer_read: READ: %s\n", fsp_str_dbg(fsp)));
758
759         smb_traffic_analyzer_send_data(handle,
760                         &s_data,
761                         vfs_id_read);
762         return s_data.len;
763 }
764
765
766 static ssize_t smb_traffic_analyzer_pread(vfs_handle_struct *handle, \
767                 files_struct *fsp, void *data, size_t n, SMB_OFF_T offset)
768 {
769         struct rw_data s_data;
770
771         s_data.len = SMB_VFS_NEXT_PREAD(handle, fsp, data, n, offset);
772         s_data.filename = fsp->fsp_name->base_name;
773         DEBUG(10, ("smb_traffic_analyzer_pread: PREAD: %s\n",
774                    fsp_str_dbg(fsp)));
775
776         smb_traffic_analyzer_send_data(handle,
777                         &s_data,
778                         vfs_id_pread);
779
780         return s_data.len;
781 }
782
783 static ssize_t smb_traffic_analyzer_write(vfs_handle_struct *handle, \
784                         files_struct *fsp, const void *data, size_t n)
785 {
786         struct rw_data s_data;
787
788         s_data.len = SMB_VFS_NEXT_WRITE(handle, fsp, data, n);
789         s_data.filename = fsp->fsp_name->base_name;
790         DEBUG(10, ("smb_traffic_analyzer_write: WRITE: %s\n",
791                    fsp_str_dbg(fsp)));
792
793         smb_traffic_analyzer_send_data(handle,
794                         &s_data,
795                         vfs_id_write);
796         return s_data.len;
797 }
798
799 static ssize_t smb_traffic_analyzer_pwrite(vfs_handle_struct *handle, \
800              files_struct *fsp, const void *data, size_t n, SMB_OFF_T offset)
801 {
802         struct rw_data s_data;
803
804         s_data.len = SMB_VFS_NEXT_PWRITE(handle, fsp, data, n, offset);
805         s_data.filename = fsp->fsp_name->base_name;
806         DEBUG(10, ("smb_traffic_analyzer_pwrite: PWRITE: %s\n", \
807                 fsp_str_dbg(fsp)));
808
809         smb_traffic_analyzer_send_data(handle,
810                         &s_data,
811                         vfs_id_pwrite);
812         return s_data.len;
813 }
814
815 static int smb_traffic_analyzer_open(vfs_handle_struct *handle, \
816         struct smb_filename *smb_fname, files_struct *fsp,\
817         int flags, mode_t mode)
818 {
819         struct open_data s_data;
820
821         s_data.result = SMB_VFS_NEXT_OPEN( handle, smb_fname, fsp,
822                         flags, mode);
823         DEBUG(10,("smb_traffic_analyzer_open: OPEN: %s\n",
824                 fsp_str_dbg(fsp)));
825         s_data.filename = fsp->fsp_name->base_name;
826         s_data.mode = mode;
827         smb_traffic_analyzer_send_data(handle,
828                         &s_data,
829                         vfs_id_open);
830         return s_data.result;
831 }
832
833 static int smb_traffic_analyzer_close(vfs_handle_struct *handle, \
834         files_struct *fsp)
835 {
836         struct close_data s_data;
837         s_data.result = SMB_VFS_NEXT_CLOSE(handle, fsp);
838         DEBUG(10,("smb_traffic_analyzer_close: CLOSE: %s\n",
839                 fsp_str_dbg(fsp)));
840         s_data.filename = fsp->fsp_name->base_name;
841         smb_traffic_analyzer_send_data(handle,
842                         &s_data,
843                         vfs_id_close);
844         return s_data.result;
845 }
846
847         
848 static struct vfs_fn_pointers vfs_smb_traffic_analyzer_fns = {
849         .connect_fn = smb_traffic_analyzer_connect,
850         .vfs_read = smb_traffic_analyzer_read,
851         .pread = smb_traffic_analyzer_pread,
852         .write = smb_traffic_analyzer_write,
853         .pwrite = smb_traffic_analyzer_pwrite,
854         .mkdir = smb_traffic_analyzer_mkdir,
855         .rename = smb_traffic_analyzer_rename,
856         .chdir = smb_traffic_analyzer_chdir,
857         .open = smb_traffic_analyzer_open,
858         .rmdir = smb_traffic_analyzer_rmdir,
859         .close_fn = smb_traffic_analyzer_close
860 };
861
862 /* Module initialization */
863 NTSTATUS vfs_smb_traffic_analyzer_init(void)
864 {
865         NTSTATUS ret = smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
866                                         "smb_traffic_analyzer",
867                                         &vfs_smb_traffic_analyzer_fns);
868
869         if (!NT_STATUS_IS_OK(ret)) {
870                 return ret;
871         }
872
873         vfs_smb_traffic_analyzer_debug_level =
874                 debug_add_class("smb_traffic_analyzer");
875
876         if (vfs_smb_traffic_analyzer_debug_level == -1) {
877                 vfs_smb_traffic_analyzer_debug_level = DBGC_VFS;
878                 DEBUG(1, ("smb_traffic_analyzer_init: Couldn't register custom"
879                          "debugging class!\n"));
880         } else {
881                 DEBUG(3, ("smb_traffic_analyzer_init: Debug class number of"
882                         "'smb_traffic_analyzer': %d\n", \
883                         vfs_smb_traffic_analyzer_debug_level));
884         }
885
886         return ret;
887 }