Restructure the module so it connects to the remote data sink
[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
23 /* abstraction for the send_over_network function */
24 #define UNIX_DOMAIN_SOCKET 1
25 #define INTERNET_SOCKET 0
26
27
28 /* Prototypes */
29
30 extern userdom_struct current_user_info;
31
32 static int vfs_smb_traffic_analyzer_debug_level = DBGC_VFS;
33
34 /* create the timestamp in sqlite compatible format */
35 static void get_timestamp(fstring str)
36 {
37         struct timeval tv;
38         struct timezone tz;
39         struct tm *tm;
40         int seconds;
41
42         gettimeofday(&tv, &tz);
43         tm=localtime(&tv.tv_sec);
44         seconds=(float) (tv.tv_usec / 1000);
45
46         fstr_sprintf(str,"%04d-%02d-%02d %02d:%02d:%02d.%03d", \
47                         tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday, \
48                         tm->tm_hour, tm->tm_min, tm->tm_sec, (int)seconds);
49
50 }
51
52 static int smb_traffic_analyzer_connMode(vfs_handle_struct *handle)
53 {
54         connection_struct *conn = handle->conn;
55         const char *Mode;
56         Mode=lp_parm_const_string(SNUM(conn), "smb_traffic_analyzer","mode", \
57                         "internet_socket");
58         if (strstr(Mode,"unix_domain_socket")) {
59                 return UNIX_DOMAIN_SOCKET;
60         } else {
61                 return INTERNET_SOCKET;
62         }
63
64 }
65
66 /* Connect to an internet socket */
67
68 static int smb_traffic_analyzer_connect_inet_socket(vfs_handle_struct *handle)
69 {
70         /* Create a streaming Socket */
71         const char *Hostname;
72         int sockfd = -1;
73         uint16_t port;
74         struct addrinfo hints;
75         struct addrinfo *ailist = NULL;
76         struct addrinfo *res = NULL;
77         connection_struct *conn = handle->conn;
78         int ret;
79
80         /* get port number, target system from the config parameters */
81         Hostname=lp_parm_const_string(SNUM(conn), "smb_traffic_analyzer",
82                                 "host", "localhost");
83
84         ZERO_STRUCT(hints);
85         /* By default make sure it supports TCP. */
86         hints.ai_socktype = SOCK_STREAM;
87         hints.ai_flags = AI_ADDRCONFIG;
88
89         ret = getaddrinfo(Hostname,
90                         NULL,
91                         &hints,
92                         &ailist);
93
94         if (ret) {
95                 DEBUG(3,("smb_traffic_analyzer_connect_inet_socket: "
96                         "getaddrinfo failed for name %s [%s]\n",
97                         Hostname,
98                         gai_strerror(ret) ));
99                 return -1;
100         }
101
102         port = atoi( lp_parm_const_string(SNUM(conn),
103                                 "smb_traffic_analyzer", "port", "9430"));
104
105         DEBUG(3,("smb_traffic_analyzer: Internet socket mode. Hostname: %s,"
106                 "Port: %i\n", Hostname, port));
107
108         for (res = ailist; res; res = res->ai_next) {
109                 struct sockaddr_storage ss;
110
111                 if (!res->ai_addr || res->ai_addrlen == 0) {
112                         continue;
113                 }
114
115                 ZERO_STRUCT(ss);
116                 memcpy(&ss, res->ai_addr, res->ai_addrlen);
117
118                 sockfd = open_socket_out(SOCK_STREAM, &ss, port, 10000);
119                 if (sockfd != -1) {
120                         break;
121                 }
122         }
123
124         if (ailist) {
125                 freeaddrinfo(ailist);
126         }
127
128         if (sockfd == -1) {
129                 DEBUG(1, ("smb_traffic_analyzer: unable to create "
130                         "socket, error is %s",
131                         strerror(errno)));
132                 return -1;
133         }
134
135         return sockfd;
136 }
137
138 /* Connect to a unix domain socket */
139
140 static int smb_traffic_analyzer_connect_unix_socket(vfs_handle_struct *handle)
141 {
142         /* Create the socket to stad */
143         int len, sock;
144         struct sockaddr_un remote;
145
146         DEBUG(7, ("smb_traffic_analyzer_connect_unix_socket: "
147                         "Unix domain socket mode. Using "
148                         "/var/tmp/stadsocket\n"));
149
150         if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
151                 DEBUG(1, ("smb_traffic_analyzer_connect_unix_socket: "
152                         "Couldn't create socket, "
153                         "make sure stad is running!\n"));
154         }
155         remote.sun_family = AF_UNIX;
156         strlcpy(remote.sun_path, "/var/tmp/stadsocket",
157                     sizeof(remote.sun_path));
158         len=strlen(remote.sun_path) + sizeof(remote.sun_family);
159         if (connect(sock, (struct sockaddr *)&remote, len) == -1 ) {
160                 DEBUG(1, ("smb_traffic_analyzer_connect_unix_socket: "
161                         "Could not connect to "
162                         "socket, make sure\nstad is running!\n"));
163                 close(sock);
164                 return -1;
165         }
166         return sock;
167 }
168
169 /* Send data over a socket */
170
171 static void smb_traffic_analyzer_send_data(vfs_handle_struct *handle,
172                                         char *str,
173                                         const char *file_name,
174                                         bool Write)
175 {
176         int *psockfd = NULL;
177         char Sender[200];
178         char TimeStamp[200];
179
180         SMB_VFS_HANDLE_GET_DATA(handle, psockfd, int, return);
181
182         if (psockfd == NULL || *psockfd == -1) {
183                 DEBUG(1, ("smb_traffic_analyzer_send_data: socket is "
184                         "closed\n"));
185                 return;
186         }
187
188         strlcpy(Sender, str, sizeof(Sender));
189         strlcat(Sender, ",\"", sizeof(Sender));
190         strlcat(Sender, get_current_username(), sizeof(Sender));
191         strlcat(Sender, "\",\"", sizeof(Sender));
192         strlcat(Sender, current_user_info.domain, sizeof(Sender));
193         strlcat(Sender, "\",\"", sizeof(Sender));
194         if (Write)
195                 strlcat(Sender, "W", sizeof(Sender));
196         else
197                 strlcat(Sender, "R", sizeof(Sender));
198         strlcat(Sender, "\",\"", sizeof(Sender));
199         strlcat(Sender, handle->conn->connectpath, sizeof(Sender));
200         strlcat(Sender, "\",\"", sizeof(Sender) - 1);
201         strlcat(Sender, file_name, sizeof(Sender) - 1);
202         strlcat(Sender, "\",\"", sizeof(Sender) - 1);
203         get_timestamp(TimeStamp);
204         strlcat(Sender, TimeStamp, sizeof(Sender) - 1);
205         strlcat(Sender, "\");", sizeof(Sender) - 1);
206         DEBUG(10, ("smb_traffic_analyzer_send_data_socket: sending %s\n",
207                         Sender));
208         if (send(*psockfd, Sender, strlen(Sender), 0) == -1 ) {
209                 DEBUG(1, ("smb_traffic_analyzer_send_data_socket: "
210                         "error sending data to socket!\n"));
211                 return ;
212         }
213 }
214
215 static void smb_traffic_analyzer_free_data(void **pptr)
216 {
217         int *pfd = *(int **)pptr;
218         if(!pfd) {
219                 return;
220         }
221         if (*pfd != -1) {
222                 close(*pfd);
223         }
224         TALLOC_FREE(pfd);
225 }
226
227 static int smb_traffic_analyzer_connect(struct vfs_handle_struct *handle,
228                          const char *service,
229                          const char *user)
230 {
231         int *pfd = TALLOC_P(handle, int);
232
233         if (!pfd) {
234                 errno = ENOMEM;
235                 return -1;
236         }
237
238         if (smb_traffic_analyzer_connMode(handle) == UNIX_DOMAIN_SOCKET) {
239                 *pfd = smb_traffic_analyzer_connect_unix_socket(handle);
240         } else {
241                 *pfd = smb_traffic_analyzer_connect_inet_socket(handle);
242         }
243         if (*pfd == -1) {
244                 return -1;
245         }
246
247         /* Store the private data. */
248         SMB_VFS_HANDLE_SET_DATA(handle, pfd, smb_traffic_analyzer_free_data,
249                                 int, return -1);
250         return SMB_VFS_NEXT_CONNECT(handle, service, user);
251 }
252
253 /* VFS Functions: write, read, pread, pwrite for now */
254
255 static ssize_t smb_traffic_analyzer_read(vfs_handle_struct *handle, \
256                                 files_struct *fsp, void *data, size_t n)
257 {
258         ssize_t result;
259         fstring Buffer;
260
261         result = SMB_VFS_NEXT_READ(handle, fsp, data, n);
262         DEBUG(10, ("smb_traffic_analyzer_read: READ: %s\n", fsp->fsp_name ));
263
264         fstr_sprintf(Buffer, "%u", (uint) result);
265
266         smb_traffic_analyzer_send_data(handle,
267                         Buffer,
268                         fsp->fsp_name,
269                         false);
270         return result;
271 }
272
273
274 static ssize_t smb_traffic_analyzer_pread(vfs_handle_struct *handle, \
275                 files_struct *fsp, void *data, size_t n, SMB_OFF_T offset)
276 {
277         ssize_t result;
278         fstring Buffer;
279
280         result = SMB_VFS_NEXT_PREAD(handle, fsp, data, n, offset);
281
282         DEBUG(10, ("smb_traffic_analyzer_pread: PREAD: %s\n", fsp->fsp_name ));
283
284         fstr_sprintf(Buffer,"%u", (uint) result);
285         smb_traffic_analyzer_send_data(handle,
286                         Buffer,
287                         fsp->fsp_name,
288                         false);
289
290         return result;
291 }
292
293 static ssize_t smb_traffic_analyzer_write(vfs_handle_struct *handle, \
294                         files_struct *fsp, const void *data, size_t n)
295 {
296         ssize_t result;
297         fstring Buffer;
298
299         result = SMB_VFS_NEXT_WRITE(handle, fsp, data, n);
300
301         DEBUG(10, ("smb_traffic_analyzer_write: WRITE: %s\n", fsp->fsp_name ));
302
303         fstr_sprintf(Buffer, "%u", (uint) result);
304         smb_traffic_analyzer_send_data(handle,
305                         Buffer,
306                         fsp->fsp_name,
307                         true);
308         return result;
309 }
310
311 static ssize_t smb_traffic_analyzer_pwrite(vfs_handle_struct *handle, \
312              files_struct *fsp, const void *data, size_t n, SMB_OFF_T offset)
313 {
314         ssize_t result;
315         fstring Buffer;
316
317         result = SMB_VFS_NEXT_PWRITE(handle, fsp, data, n, offset);
318
319         DEBUG(10, ("smb_traffic_analyzer_pwrite: PWRITE: %s\n", fsp->fsp_name ));
320
321         fstr_sprintf(Buffer, "%u", (uint) result);
322         smb_traffic_analyzer_send_data(handle,
323                         Buffer,
324                         fsp->fsp_name,
325                         true);
326         return result;
327 }
328
329 /* VFS operations we use */
330
331 static vfs_op_tuple smb_traffic_analyzer_tuples[] = {
332
333         {SMB_VFS_OP(smb_traffic_analyzer_connect), SMB_VFS_OP_CONNECT,
334          SMB_VFS_LAYER_LOGGER},
335         {SMB_VFS_OP(smb_traffic_analyzer_read), SMB_VFS_OP_READ,
336          SMB_VFS_LAYER_LOGGER},
337         {SMB_VFS_OP(smb_traffic_analyzer_pread), SMB_VFS_OP_PREAD,
338          SMB_VFS_LAYER_LOGGER},
339         {SMB_VFS_OP(smb_traffic_analyzer_write), SMB_VFS_OP_WRITE,
340          SMB_VFS_LAYER_LOGGER},
341         {SMB_VFS_OP(smb_traffic_analyzer_pwrite), SMB_VFS_OP_PWRITE,
342          SMB_VFS_LAYER_LOGGER},
343         {SMB_VFS_OP(NULL),SMB_VFS_OP_NOOP,SMB_VFS_LAYER_NOOP}
344 };
345
346 /* Module initialization */
347
348 NTSTATUS vfs_smb_traffic_analyzer_init(void)
349 {
350         NTSTATUS ret = smb_register_vfs(SMB_VFS_INTERFACE_VERSION, \
351                 "smb_traffic_analyzer", smb_traffic_analyzer_tuples);
352
353         if (!NT_STATUS_IS_OK(ret)) {
354                 return ret;
355         }
356
357         vfs_smb_traffic_analyzer_debug_level =
358                 debug_add_class("smb_traffic_analyzer");
359
360         if (vfs_smb_traffic_analyzer_debug_level == -1) {
361                 vfs_smb_traffic_analyzer_debug_level = DBGC_VFS;
362                 DEBUG(1, ("smb_traffic_analyzer_init: Couldn't register custom"
363                          "debugging class!\n"));
364         } else {
365                 DEBUG(3, ("smb_traffic_analyzer_init: Debug class number of"
366                         "'smb_traffic_analyzer': %d\n", \
367                         vfs_smb_traffic_analyzer_debug_level));
368         }
369
370         return ret;
371 }