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 34static char *netbiosname; 35static char packet[BUFFER_SIZE]; 36 37static 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 53static 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 78static 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 119static 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 170static 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 220int 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} 246