Initial import
[samba] / source / utils / smbfilter.c
1 /* 
2    Unix SMB/CIFS implementation.
3    SMB filter/socket plugin
4    Copyright (C) Andrew Tridgell 1999
5    
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #include "includes.h"
22
23 #define SECURITY_MASK 0
24 #define SECURITY_SET  0
25
26 /* this forces non-unicode */
27 #define CAPABILITY_MASK 0
28 #define CAPABILITY_SET  0
29
30 /* and non-unicode for the client too */
31 #define CLI_CAPABILITY_MASK 0
32 #define CLI_CAPABILITY_SET  0
33
34 static char *netbiosname;
35 static char packet[BUFFER_SIZE];
36
37 static void save_file(const char *fname, void *ppacket, size_t length)
38 {
39         int fd;
40         fd = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0644);
41         if (fd == -1) {
42                 perror(fname);
43                 return;
44         }
45         if (write(fd, ppacket, length) != length) {
46                 fprintf(stderr,"Failed to write %s\n", fname);
47                 return;
48         }
49         close(fd);
50         printf("Wrote %ld bytes to %s\n", (unsigned long)length, fname);
51 }
52
53 static void filter_reply(char *buf)
54 {
55         int msg_type = CVAL(buf,0);
56         int type = CVAL(buf,smb_com);
57         unsigned x;
58
59         if (msg_type) return;
60
61         switch (type) {
62
63         case SMBnegprot:
64                 /* force the security bits */
65                 x = CVAL(buf, smb_vwv1);
66                 x = (x | SECURITY_SET) & ~SECURITY_MASK;
67                 SCVAL(buf, smb_vwv1, x);
68
69                 /* force the capabilities */
70                 x = IVAL(buf,smb_vwv9+1);
71                 x = (x | CAPABILITY_SET) & ~CAPABILITY_MASK;
72                 SIVAL(buf, smb_vwv9+1, x);
73                 break;
74
75         }
76 }
77
78 static void filter_request(char *buf)
79 {
80         int msg_type = CVAL(buf,0);
81         int type = CVAL(buf,smb_com);
82         pstring name1,name2;
83         unsigned x;
84
85         if (msg_type) {
86                 /* it's a netbios special */
87                 switch (msg_type) {
88                 case 0x81:
89                         /* session request */
90                         name_extract(buf,4,name1);
91                         name_extract(buf,4 + name_len(buf + 4),name2);
92                         d_printf("sesion_request: %s -> %s\n",
93                                  name1, name2);
94                         if (netbiosname) {
95                                 /* replace the destination netbios name */
96                                 name_mangle(netbiosname, buf+4, 0x20);
97                         }
98                 }
99                 return;
100         }
101
102         /* it's an ordinary SMB request */
103         switch (type) {
104         case SMBsesssetupX:
105                 /* force the client capabilities */
106                 x = IVAL(buf,smb_vwv11);
107                 d_printf("SMBsesssetupX cap=0x%08x\n", x);
108                 d_printf("pwlen=%d/%d\n", SVAL(buf, smb_vwv7), SVAL(buf, smb_vwv8));
109                 system("mv sessionsetup.dat sessionsetup1.dat");
110                 save_file("sessionsetup.dat", smb_buf(buf), SVAL(buf, smb_vwv7));
111                 x = (x | CLI_CAPABILITY_SET) & ~CLI_CAPABILITY_MASK;
112                 SIVAL(buf, smb_vwv11, x);
113                 break;
114         }
115
116 }
117
118
119 static void filter_child(int c, struct in_addr dest_ip)
120 {
121         int s;
122
123         /* we have a connection from a new client, now connect to the server */
124         s = open_socket_out(SOCK_STREAM, &dest_ip, 445, LONG_CONNECT_TIMEOUT);
125
126         if (s == -1) {
127                 d_printf("Unable to connect to %s\n", inet_ntoa(dest_ip));
128                 exit(1);
129         }
130
131         while (c != -1 || s != -1) {
132                 fd_set fds;
133                 int num;
134                 
135                 FD_ZERO(&fds);
136                 if (s != -1) FD_SET(s, &fds);
137                 if (c != -1) FD_SET(c, &fds);
138
139                 num = sys_select_intr(MAX(s+1, c+1),&fds,NULL,NULL,NULL);
140                 if (num <= 0) continue;
141                 
142                 if (c != -1 && FD_ISSET(c, &fds)) {
143                         if (!receive_smb(c, packet, 0)) {
144                                 d_printf("client closed connection\n");
145                                 exit(0);
146                         }
147                         filter_request(packet);
148                         if (!send_smb(s, packet)) {
149                                 d_printf("server is dead\n");
150                                 exit(1);
151                         }                       
152                 }
153                 if (s != -1 && FD_ISSET(s, &fds)) {
154                         if (!receive_smb(s, packet, 0)) {
155                                 d_printf("server closed connection\n");
156                                 exit(0);
157                         }
158                         filter_reply(packet);
159                         if (!send_smb(c, packet)) {
160                                 d_printf("client is dead\n");
161                                 exit(1);
162                         }                       
163                 }
164         }
165         d_printf("Connection closed\n");
166         exit(0);
167 }
168
169
170 static void start_filter(char *desthost)
171 {
172         int s, c;
173         struct in_addr dest_ip;
174
175         CatchChild();
176
177         /* start listening on port 445 locally */
178         s = open_socket_in(SOCK_STREAM, 445, 0, 0, True);
179         
180         if (s == -1) {
181                 d_printf("bind failed\n");
182                 exit(1);
183         }
184
185         if (listen(s, 5) == -1) {
186                 d_printf("listen failed\n");
187         }
188
189         if (!resolve_name(desthost, &dest_ip, 0x20)) {
190                 d_printf("Unable to resolve host %s\n", desthost);
191                 exit(1);
192         }
193
194         while (1) {
195                 fd_set fds;
196                 int num;
197                 struct sockaddr addr;
198                 socklen_t in_addrlen = sizeof(addr);
199                 
200                 FD_ZERO(&fds);
201                 FD_SET(s, &fds);
202
203                 num = sys_select_intr(s+1,&fds,NULL,NULL,NULL);
204                 if (num > 0) {
205                         c = accept(s, &addr, &in_addrlen);
206                         if (c != -1) {
207                                 if (fork() == 0) {
208                                         close(s);
209                                         filter_child(c, dest_ip);
210                                         exit(0);
211                                 } else {
212                                         close(c);
213                                 }
214                         }
215                 }
216         }
217 }
218
219
220 int main(int argc, char *argv[])
221 {
222         char *desthost;
223         pstring configfile;
224
225         setup_logging(argv[0],True);
226   
227         pstrcpy(configfile,dyn_CONFIGFILE);
228  
229         if (argc < 2) {
230                 fprintf(stderr,"smbfilter <desthost> <netbiosname>\n");
231                 exit(1);
232         }
233
234         desthost = argv[1];
235         if (argc > 2) {
236                 netbiosname = argv[2];
237         }
238
239         if (!lp_load(configfile,True,False,False)) {
240                 d_printf("Unable to load config file\n");
241         }
242
243         start_filter(desthost);
244         return 0;
245 }