SMB traffic analyzer vfs module from Holger Hetterich <hhetter@novell.com>
[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  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, see <http://www.gnu.org/licenses/>.
19  */
20
21 #include "includes.h"
22 #include "safe_string.h"
23 #include <sys/socket.h>
24 #include <stdlib.h>
25 #include <sys/time.h>
26
27
28 /* abstraction for the send_over_network function */
29 #define UNIX_DOMAIN_SOCKET 1
30 #define INTERNET_SOCKET 0
31
32
33 /* Prototypes */
34
35 extern userdom_struct current_user_info;
36
37 static int vfs_smb_traffic_analyzer_debug_level = DBGC_VFS;
38
39 NTSTATUS init_samba_module(void);
40
41 static ssize_t smb_traffic_analyzer_write(vfs_handle_struct *handle,
42                 files_struct *fsp, const void *data, size_t n);
43
44 static ssize_t smb_traffic_analyzer_read(vfs_handle_struct *handle,
45                 files_struct *fsp, void *data, size_t n);
46
47 static ssize_t smb_traffic_analyzer_pwrite(vfs_handle_struct *handle,
48                 files_struct *fsp, const void *data, size_t n,
49                 SMB_OFF_T offset);
50
51 static ssize_t smb_traffic_analyzer_pread(vfs_handle_struct *handle,
52                 files_struct *fsp, void *data, size_t n, SMB_OFF_T offset);
53
54
55 /* VFS operations we use */
56
57 static vfs_op_tuple smb_traffic_analyzer_tuples[] = {
58
59         {SMB_VFS_OP(smb_traffic_analyzer_read), SMB_VFS_OP_READ,
60          SMB_VFS_LAYER_LOGGER},
61         {SMB_VFS_OP(smb_traffic_analyzer_pread), SMB_VFS_OP_PREAD,
62          SMB_VFS_LAYER_LOGGER},
63         {SMB_VFS_OP(smb_traffic_analyzer_write), SMB_VFS_OP_WRITE,
64          SMB_VFS_LAYER_LOGGER},
65         {SMB_VFS_OP(smb_traffic_analyzer_pwrite), SMB_VFS_OP_PWRITE,
66          SMB_VFS_LAYER_LOGGER},
67         {SMB_VFS_OP(NULL),SMB_VFS_OP_NOOP,SMB_VFS_LAYER_NOOP}
68
69         };
70
71
72 /* Module initialization */
73
74 NTSTATUS init_samba_module(void)
75 {
76         NTSTATUS ret = smb_register_vfs(SMB_VFS_INTERFACE_VERSION, \
77                 "smb_traffic_analyzer", smb_traffic_analyzer_tuples);
78
79         if (!NT_STATUS_IS_OK(ret))
80                 return ret;
81
82         vfs_smb_traffic_analyzer_debug_level =
83                 debug_add_class("smb_traffic_analyzer");
84
85         if (vfs_smb_traffic_analyzer_debug_level == -1) {
86                 vfs_smb_traffic_analyzer_debug_level = DBGC_VFS;
87                 DEBUG(1, ("smb_traffic_analyzer: Couldn't register custom"
88                          "debugging class!\n"));
89         } else {
90                 DEBUG(3, ("smb_traffic_analyzer: Debug class number of"
91                         "'smb_traffic_analyzer': %d\n", \
92                         vfs_smb_traffic_analyzer_debug_level));
93         }
94
95         return ret;
96 }
97
98 /* create the timestamp in sqlite compatible format */
99 static void get_timestamp( char *String )
100 {
101         struct timeval tv;
102         struct timezone tz;
103         struct tm *tm;
104         int seconds;
105
106         gettimeofday(&tv, &tz);
107         tm=localtime(&tv.tv_sec);
108         seconds=(float) (tv.tv_usec / 1000);
109
110         fstr_sprintf(String,"%04d-%02d-%02d %02d:%02d:%02d.%03d", \
111                         tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday, \
112                         tm->tm_hour, tm->tm_min, tm->tm_sec, (int)seconds);
113
114 }
115
116 static int smb_traffic_analyzer_connMode( vfs_handle_struct *handle)
117 {
118         connection_struct *conn = handle->conn;
119         const char *Mode;
120         Mode=lp_parm_const_string(SNUM(conn), "smb_traffic_analyzer","mode", \
121                         "internet_socket");
122         if (strstr(Mode,"unix_domain_socket")) {
123                 return UNIX_DOMAIN_SOCKET;
124         } else {
125                 return INTERNET_SOCKET;
126         }
127
128 }
129
130
131
132 /* Send data over a internet socket */
133 static void smb_traffic_analyzer_send_data_inet_socket( char *String,
134                         vfs_handle_struct *handle, const char *file_name,
135                         bool Write)
136 {
137          /* Create a streaming Socket */
138         const char *Hostname;
139         int sockfd, result;
140         int port;
141         struct sockaddr_in their_addr;
142         struct hostent *hp;
143         char Sender[200];
144         char TimeStamp[200];
145         int yes = 1;
146         connection_struct *conn;
147
148         if ((sockfd=socket(AF_INET, SOCK_STREAM,0)) == -1) {
149                 DEBUG(1, ("unable to create socket, error is %s", 
150                           strerror(errno)));
151                 return;
152         }
153         if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, \
154                                                         sizeof(int)) == -1) {
155                 DEBUG(1, ("unable to set socket options, error is %s", 
156                           strerror(errno)));
157                 return;
158         }
159         /* get port number, target system from the config parameters */
160         conn=handle->conn;
161
162         Hostname=lp_parm_const_string(SNUM(conn), "smb_traffic_analyzer", 
163                 "host", "localhost");
164
165         port = atoi( lp_parm_const_string(SNUM(conn), 
166                                 "smb_traffic_analyzer", "port", "9430"));
167
168         hp = gethostbyname(Hostname);
169         if (hp == NULL) {
170                 DEBUG(1, ("smb_traffic_analyzer: Unkown Hostname of"
171                         "target system!\n"));
172         }
173         DEBUG(3,("smb_traffic_analyzer: Internet socket mode. Hostname: %s,"
174                 "Port: %i\n", Hostname, port));
175
176         their_addr.sin_family = AF_INET;
177         their_addr.sin_port = htons(port);
178         their_addr.sin_addr.s_addr = INADDR_ANY;
179         memset(their_addr.sin_zero, '\0', sizeof(their_addr.sin_zero));
180         memcpy(hp->h_addr, &their_addr.sin_addr, hp->h_length);
181         their_addr.sin_port=htons(port);
182         result=connect( sockfd, &their_addr, sizeof( struct sockaddr_in));
183         if ( result < 0 ) {
184                 DEBUG(1, ("smb_traffic_analyzer: Couldn't connect to inet"
185                         "socket!\n"));
186         }
187         safe_strcpy(Sender, String, sizeof(Sender) - 1);
188         safe_strcat(Sender, ",\"", sizeof(Sender) - 1);
189         safe_strcat(Sender, get_current_username(), sizeof(Sender) - 1);
190         safe_strcat(Sender, "\",\"", sizeof(Sender) - 1);
191         safe_strcat(Sender, current_user_info.domain, sizeof(Sender) - 1);
192         safe_strcat(Sender, "\",\"", sizeof(Sender) - 1);
193         if (Write)
194                 safe_strcat(Sender, "W", sizeof(Sender) - 1);
195         else
196                 safe_strcat(Sender, "R", sizeof(Sender) - 1);
197         safe_strcat(Sender, "\",\"", sizeof(Sender) - 1);
198         safe_strcat(Sender, handle->conn->connectpath, sizeof(Sender) - 1);
199         safe_strcat(Sender, "\",\"", sizeof(Sender) - 1);
200         safe_strcat(Sender, file_name, sizeof(Sender) - 1);
201         safe_strcat(Sender, "\",\"", sizeof(Sender) - 1);
202         get_timestamp(TimeStamp);
203         safe_strcat(Sender, TimeStamp, sizeof(Sender) - 1);
204         safe_strcat(Sender, "\");", sizeof(Sender) - 1);
205         DEBUG(10, ("smb_traffic_analyzer: sending %s\n", Sender));
206         if ( send(sockfd, Sender, strlen(Sender), 0) == -1 ) {
207                 DEBUG(1, ("smb_traffic_analyzer: error sending data to socket!\n"));
208                 return ;
209         }
210
211         /* one operation, close the socket */
212         close(sockfd);
213 }
214
215
216
217 /* Send data over a unix domain socket */
218 static void smb_traffic_analyzer_send_data_unix_socket( char *String ,
219                         vfs_handle_struct *handle, const char *file_name, 
220                         bool Write)
221 {
222         /* Create the socket to stad */
223         int len, sock;
224         struct sockaddr_un remote;
225         char Sender[200];
226         char TimeStamp[200];
227         DEBUG(7, ("smb_traffic_analyzer: Unix domain socket mode. Using "
228                         "/var/tmp/stadsocket\n"));
229         if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
230                 DEBUG(1, ("smb_traffic_analyzer: Couldn create socket,"
231                         "make sure stad is running!\n"));
232         }
233         remote.sun_family = AF_UNIX;
234         safe_strcpy(remote.sun_path, "/var/tmp/stadsocket", 
235                     sizeof(remote.sun_path) - 1);
236         len=strlen(remote.sun_path) + sizeof(remote.sun_family);
237         if (connect(sock, (struct sockaddr *)&remote, len) == -1 ) {
238                 DEBUG(1, ("smb_traffic_analyzer: Could not connect to"
239                         "socket, make sure\nstad is running!\n"));
240         }
241         safe_strcpy(Sender, String, sizeof(Sender) - 1);
242         safe_strcat(Sender, ",\"", sizeof(Sender) - 1);
243         safe_strcat(Sender, get_current_username(), sizeof(Sender) - 1);
244         safe_strcat(Sender,"\",\"",sizeof(Sender) - 1);
245         safe_strcat(Sender, current_user_info.domain, sizeof(Sender) - 1);
246         safe_strcat(Sender, "\",\"", sizeof(Sender) - 1);
247         if (Write)
248                 safe_strcat(Sender, "W", sizeof(Sender) - 1);
249         else
250                 safe_strcat(Sender, "R", sizeof(Sender) - 1);
251         safe_strcat(Sender, "\",\"", sizeof(Sender) - 1);
252         safe_strcat(Sender, handle->conn->connectpath, sizeof(Sender) - 1);
253         safe_strcat(Sender, "\",\"", sizeof(Sender) - 1);
254         safe_strcat(Sender, file_name, sizeof(Sender) - 1);
255         safe_strcat(Sender, "\",\"", sizeof(Sender) - 1);
256         get_timestamp(TimeStamp);
257         safe_strcat(Sender, TimeStamp, sizeof(Sender) - 1);
258         safe_strcat(Sender, "\");", sizeof(Sender) - 1);
259
260         DEBUG(10, ("smb_traffic_analyzer: sending %s\n", Sender));
261         if ( send(sock, Sender, strlen(Sender), 0) == -1 ) {
262                 DEBUG(1, ("smb_traffic_analyzer: error sending data to"
263                         "socket!\n"));
264                 return;
265         }
266
267         /* one operation, close the socket */
268         close(sock);
269
270         return;
271 }
272
273 static void smb_traffic_analyzer_send_data( char *Buffer , vfs_handle_struct \
274                         *handle, char *file_name, bool Write, files_struct *fsp)
275 {
276
277         if (smb_traffic_analyzer_connMode(handle) == UNIX_DOMAIN_SOCKET) {
278                 smb_traffic_analyzer_send_data_unix_socket(Buffer, handle, \
279                                                         fsp->fsp_name, Write);
280         } else {
281                 smb_traffic_analyzer_send_data_inet_socket(Buffer, handle, \
282                                                         fsp->fsp_name, Write);
283         }
284 }
285
286
287
288 /* VFS Functions: write, read, pread, pwrite for now */
289
290 static ssize_t smb_traffic_analyzer_read(vfs_handle_struct *handle, \
291                                 files_struct *fsp, void *data, size_t n)
292 {
293         ssize_t result;
294         char Buffer[100];
295
296         result = SMB_VFS_NEXT_READ(handle, fsp, data, n);
297         DEBUG(10, ("smb_traffic_analyzer: READ: %s\n", fsp->fsp_name ));
298
299         fstr_sprintf(Buffer, "%u", (uint) result);
300
301         smb_traffic_analyzer_send_data(Buffer, handle, fsp->fsp_name, false, fsp);
302         return result;
303 }
304
305
306 static ssize_t smb_traffic_analyzer_pread(vfs_handle_struct *handle, \
307                 files_struct *fsp, void *data, size_t n, SMB_OFF_T offset)
308 {
309         ssize_t result;
310         char Buffer[100];
311
312         result = SMB_VFS_NEXT_PREAD(handle, fsp, data, n, offset);
313
314         DEBUG(10, ("smb_traffic_analyzer: READ: %s\n", fsp->fsp_name ));
315
316         fstr_sprintf(Buffer,"%u", (uint) result);
317         smb_traffic_analyzer_send_data(Buffer, handle, fsp->fsp_name, false, fsp);
318
319         return result;
320 }
321
322 static ssize_t smb_traffic_analyzer_write(vfs_handle_struct *handle, \
323                         files_struct *fsp, const void *data, size_t n)
324 {
325         ssize_t result;
326         char Buffer[100];
327
328         result = SMB_VFS_NEXT_WRITE(handle, fsp, data, n);
329
330         DEBUG(10, ("smb_traffic_analyzer: WRITE: %s\n", fsp->fsp_name ));
331
332         fstr_sprintf(Buffer, "%u", (uint) result);
333         smb_traffic_analyzer_send_data(Buffer, handle, fsp->fsp_name, \
334                                                                 true, fsp );
335         return result;
336 }
337
338 static ssize_t smb_traffic_analyzer_pwrite(vfs_handle_struct *handle, \
339              files_struct *fsp, const void *data, size_t n, SMB_OFF_T offset)
340 {
341         ssize_t result;
342         char Buffer[100];
343
344         result = SMB_VFS_NEXT_PWRITE(handle, fsp, data, n, offset);
345
346         DEBUG(10, ("smb_traffic_analyzer: PWRITE: %s\n", fsp->fsp_name ));
347
348         fstr_sprintf(Buffer, "%u", (uint) result);
349         smb_traffic_analyzer_send_data(Buffer, handle, fsp->fsp_name, true, fsp);
350         return result;
351 }
352