From fc93261150812a5c74f713776ccb89226a2181e8 Mon Sep 17 00:00:00 2001 From: Mike McCormack <mike_mccormack@start.com.au> Date: Tue, 12 Mar 2002 19:24:04 +0000 Subject: [PATCH] Begin to make wine an SMB client. --- files/Makefile.in | 1 + files/file.c | 10 +- files/smb.c | 1069 ++++++++++++++++++++++++++++++++ files/smb.h | 100 +++ include/wine/server_protocol.h | 46 +- server/Makefile.in | 1 + server/protocol.def | 28 +- server/request.h | 4 + server/smb.c | 192 ++++++ server/trace.c | 36 ++ 10 files changed, 1481 insertions(+), 6 deletions(-) create mode 100644 files/smb.c create mode 100644 files/smb.h create mode 100644 server/smb.c diff --git a/files/Makefile.in b/files/Makefile.in index 92127b76b2f..483914cfaa9 100644 --- a/files/Makefile.in +++ b/files/Makefile.in @@ -12,6 +12,7 @@ C_SRCS = \ drive.c \ file.c \ profile.c \ + smb.c \ tape.c all: $(MODULE).o diff --git a/files/file.c b/files/file.c index fb28a9ae13d..0bc85acd25b 100644 --- a/files/file.c +++ b/files/file.c @@ -56,6 +56,8 @@ #include "heap.h" #include "msdos.h" #include "wincon.h" + +#include "smb.h" #include "wine/debug.h" #include "wine/server.h" @@ -74,6 +76,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(file); static HANDLE dos_handles[DOS_TABLE_SIZE]; +extern WINAPI HANDLE FILE_SmbOpen(LPCSTR name); /*********************************************************************** * FILE_ConvertOFMode @@ -480,9 +483,8 @@ HANDLE WINAPI CreateFileA( LPCSTR filename, DWORD access, DWORD sharing, /* If the name still starts with '\\', it's a UNC name. */ if (!strncmp(filename, "\\\\", 2)) { - FIXME("UNC name (%s) not supported.\n", filename ); - SetLastError( ERROR_PATH_NOT_FOUND ); - return INVALID_HANDLE_VALUE; + ret = SMB_CreateFileA(filename, access, sharing, sa, creation, attributes, template ); + goto done; } /* If the name contains a DOS wild card (* or ?), do no create a file */ @@ -1531,6 +1533,8 @@ BOOL WINAPI ReadFile( HANDLE hFile, LPVOID buffer, DWORD bytesToRead, } switch(type) { + case FD_TYPE_SMB: + return SMB_ReadFile(hFile, buffer, bytesToRead, bytesRead, NULL); case FD_TYPE_CONSOLE: return ReadConsoleA(hFile, buffer, bytesToRead, bytesRead, NULL); diff --git a/files/smb.c b/files/smb.c new file mode 100644 index 00000000000..2264d35d6f0 --- /dev/null +++ b/files/smb.c @@ -0,0 +1,1069 @@ +/* + * Copyright (C) 2002 Mike McCormack + * + * CIFS implementation for WINE + * + * This is a WINE's implementation of the Common Internet File System + * + * for specification see: + * + * http://www.codefx.com/CIFS_Explained.htm + * http://www.ubiqx.org/cifs/rfc-draft/rfc1002.html + * http://www.ubiqx.org/cifs/rfc-draft/draft-leach-cifs-v1-spec-02.html + * http://ubiqx.org/cifs/ + * http://www.samba.org + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "config.h" +#include "wine/port.h" + +#include <assert.h> +#include <ctype.h> +#include <errno.h> +#include <fcntl.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#ifdef HAVE_SYS_ERRNO_H +#include <sys/errno.h> +#endif +#include <sys/types.h> +#include <sys/stat.h> +#ifdef HAVE_SYS_MMAN_H +#include <sys/mman.h> +#endif +#include <sys/time.h> +#include <sys/poll.h> +#include <time.h> +#include <unistd.h> +#include <utime.h> +#include <sys/socket.h> +#include <sys/types.h> +#include <netinet/ip.h> +#include <arpa/inet.h> + +#include "winerror.h" +#include "windef.h" +#include "winbase.h" +#include "file.h" +#include "heap.h" + +#include "smb.h" + +#include "wine/server.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(file); + +#define MAX_HOST_NAME 15 +#define NB_TIMEOUT 10000 + +USHORT SMB_MultiplexId = 0; + +static int netbios_name(const char *p, unsigned char *buffer) +{ + char ch; + int i,len=0; + + buffer[len++]=' '; + for(i=0; i<=MAX_HOST_NAME; i++) + { + if(i<MAX_HOST_NAME) + { + if(*p) + ch = *p++&0xdf; /* add character from hostname */ + else + ch = ' '; /* add padding */ + } + else + ch = 0; /* add terminator */ + buffer[len++] = ((ch&0xf0) >> 4) + 'A'; + buffer[len++] = (ch&0x0f) + 'A'; + } + buffer[len++] = 0; /* add second terminator */ + return len; +} + +static DWORD NB_NameReq(LPCSTR host, unsigned char *buffer, int len) +{ + int trn = 1234,i=0; + + NBR_ADDWORD(&buffer[i],trn); i+=2; + NBR_ADDWORD(&buffer[i],0x0110); i+=2; + NBR_ADDWORD(&buffer[i],0x0001); i+=2; + NBR_ADDWORD(&buffer[i],0x0000); i+=2; + NBR_ADDWORD(&buffer[i],0x0000); i+=2; + NBR_ADDWORD(&buffer[i],0x0000); i+=2; + + i += netbios_name(host,&buffer[i]); + + NBR_ADDWORD(&buffer[i],0x0020); i+=2; + NBR_ADDWORD(&buffer[i],0x0001); i+=2; + + ERR("packet is %d bytes in length\n",i); + + { + int j; + for(j=0; j<i; j++) + printf("%02x%c",buffer[j],(((j+1)%16)&&((j+1)!=j))?' ':'\n'); + } + + return i; +} + +/* unc = \\hostname\share\file... */ +static BOOL UNC_SplitName(LPSTR unc, LPSTR *hostname, LPSTR *share, LPSTR *file) +{ + char *p; + + ERR("%s\n",unc); + + p = strchr(unc,'\\'); + if(!p) + return FALSE; + p = strchr(p+1,'\\'); + if(!p) + return FALSE; + *hostname=++p; + + p = strchr(p,'\\'); + if(!p) + return FALSE; + *p=0; + *share = ++p; + + p = strchr(p,'\\'); + if(!p) + return FALSE; + *p=0; + *file = ++p; + + return TRUE; +} + +static BOOL NB_Lookup(LPCSTR host, struct sockaddr_in *addr) +{ + int fd,on=1,r,len; + struct pollfd fds; + struct sockaddr_in sin; + unsigned char buffer[256]; + + fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); + if(fd<0) + return FALSE; + + r = setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &on, sizeof on); + if(r<0) + return FALSE; + + if(0==inet_aton("255.255.255.255", (struct in_addr *)&sin.sin_addr.s_addr)) + { + FIXME("Error getting bcast address\n"); + return FALSE; + } + sin.sin_family = AF_INET; + sin.sin_port = htons(137); + + len = NB_NameReq(host,buffer,sizeof buffer); + if(len<=0) + return FALSE; + + r = sendto(fd, buffer, len, 0, &sin, sizeof sin); + if(r<0) + { + FIXME("Error sending packet\n"); + return FALSE; + } + + fds.fd = fd; + fds.events = POLLIN; + fds.revents = 0; + + r = poll(&fds,1,NB_TIMEOUT); + if(r!=1) + return FALSE; + + close(fd); + TRACE("Got response!\n"); + return TRUE; +} + +#define NB_FIRST 0x40 + +#define NB_HDRSIZE 4 + +#define NB_SESSION_MSG 0x00 +#define NB_SESSION_REQ 0x81 + +/* RFC 1002, section 4.3.2 */ +static BOOL NB_SessionReq(int fd, char *called, char *calling) +{ + unsigned char buffer[0x100]; + int len = 0,r; + struct pollfd fds; + + ERR("called %s, calling %s\n",called,calling); + + buffer[0] = NB_SESSION_REQ; + buffer[1] = NB_FIRST; + + netbios_name(called, &buffer[NB_HDRSIZE]); + len += 34; + netbios_name(calling, &buffer[NB_HDRSIZE+len]); + len += 34; + + NBR_ADDWORD(&buffer[2],len); + + /* for(i=0; i<(len+NB_HDRSIZE); i++) + DPRINTF("%02X%c",buffer[i],(((i+1)!=(len+4))&&((i+1)%16))?' ':'\n'); */ + + r = write(fd,buffer,len+4); + if(r<0) + { + ERR("Write failed\n"); + return FALSE; + } + + fds.fd = fd; + fds.events = POLLIN; + fds.revents = 0; + + r = poll(&fds,1,NB_TIMEOUT); + if(r!=1) + { + ERR("Poll failed\n"); + return FALSE; + } + + r = read(fd, buffer, NB_HDRSIZE); + if((r!=NB_HDRSIZE) || (buffer[0]!=0x82)) + { + ERR("Received %d bytes\n",r); + ERR("%02x %02x %02x %02x\n", buffer[0],buffer[1],buffer[2],buffer[3]); + return FALSE; + } + + return TRUE; +} + +static BOOL NB_SendData(int fd, unsigned char *data, int size) +{ + unsigned char buffer[NB_HDRSIZE]; + int r; + + /* CHECK: is it always OK to do this in two writes? */ + /* perhaps use scatter gather sendmsg instead? */ + + buffer[0] = NB_SESSION_MSG; + buffer[1] = NB_FIRST; + NBR_ADDWORD(&buffer[2],size); + + r = write(fd, buffer, NB_HDRSIZE); + if(r!=NB_HDRSIZE) + return FALSE; + + r = write(fd, data, size); + if(r!=size) + { + ERR("write failed\n"); + return FALSE; + } + + return TRUE; +} + +static BOOL NB_RecvData(int fd, unsigned char *data, int *outlen) +{ + int r,len; + unsigned char buffer[NB_HDRSIZE]; + + r = read(fd, buffer, NB_HDRSIZE); + if((r!=NB_HDRSIZE) || (buffer[0]!=NB_SESSION_MSG)) + { + ERR("Received %d bytes\n",r); + return FALSE; + } + + len = NBR_GETWORD(&buffer[2]); + r = read(fd, data, len); + if(len!=r) + { + ERR("Received %d bytes\n",r); + return FALSE; + } + *outlen = len; + + return TRUE; +} + +static BOOL NB_Transaction(int fd, unsigned char *buffer, int len, int *outlen) +{ + int r,i; + struct pollfd fds; + + DPRINTF("Sending request:\n"); + for(i=0; i<len; i++) + DPRINTF("%02X%c",buffer[i],(((i+1)!=len)&&((i+1)%16))?' ':'\n'); + + if(!NB_SendData(fd,buffer,len)) + return FALSE; + + fds.fd = fd; + fds.events = POLLIN; + fds.revents = 0; + + r = poll(&fds,1,NB_TIMEOUT); + if(r!=1) + { + ERR("Poll failed\n"); + return FALSE; + } + + if(!NB_RecvData(fd, buffer, outlen)) + return FALSE; + + len = *outlen; + DPRINTF("Got response:\n"); + for(i=0; i<len; i++) + DPRINTF("%02X%c",buffer[i],(((i+1)!=len)&&((i+1)%16))?' ':'\n'); + + return TRUE; +} + +#define SMB_ADDHEADER(b,l) { b[(l)++]=0xff; b[(l)++]='S'; b[(l)++]='M'; b[(l)++]='B'; } +#define SMB_ADDERRINFO(b,l) { b[(l)++]=0; b[(l)++]=0; b[(l)++]=0; b[(l)++]=0; } +#define SMB_ADDPADSIG(b,l) { memset(&b[l],0,12); l+=12; } + +#define SMB_ERRCLASS 5 +#define SMB_ERRCODE 7 +#define SMB_TREEID 24 +#define SMB_PROCID 26 +#define SMB_USERID 28 +#define SMB_PLEXID 30 +#define SMB_PCOUNT 32 +#define SMB_HDRSIZE 33 + +static DWORD SMB_GetError(unsigned char *buffer) +{ + if(buffer[SMB_ERRCLASS]==0) + return STATUS_SUCCESS; + /* FIXME: return propper error codes */ + return STATUS_INVALID_PARAMETER; +} + +static int SMB_Header(unsigned char *buffer, unsigned char command, USHORT tree_id, USHORT user_id) +{ + int len = 0; + DWORD id; + + /* 0 */ + SMB_ADDHEADER(buffer,len); + + /* 4 */ + buffer[len++] = command; + + /* 5 */ + SMB_ADDERRINFO(buffer,len) + + /* 9 */ + buffer[len++] = 0x00; /* flags */ + SMB_ADDWORD(&buffer[len],1); len += 2; /* flags2 */ + + /* 12 */ + SMB_ADDPADSIG(buffer,len) + + /* 24 */ + SMB_ADDWORD(&buffer[len],tree_id); len += 2; /* treeid */ + id = GetCurrentThreadId(); + SMB_ADDWORD(&buffer[len],id); len += 2; /* process id */ + SMB_ADDWORD(&buffer[len],user_id); len += 2; /* user id */ + SMB_ADDWORD(&buffer[len],SMB_MultiplexId); len += 2; /* multiplex id */ + SMB_MultiplexId++; + + return len; +} + +static const char *SMB_ProtocolDialect = "NT LM 0.12"; +/* = "Windows for Workgroups 3.1a"; */ + +/* FIXME: support multiple SMB dialects */ +static BOOL SMB_NegotiateProtocol(int fd, USHORT *dialect) +{ + unsigned char buffer[0x100]; + int buflen,len = 0; + + ERR("\n"); + + memset(buffer,0,sizeof buffer); + + len = SMB_Header(buffer, SMB_COM_NEGOTIATE, 0, 0); + + /* parameters */ + buffer[len++] = 0; /* no parameters */ + + /* command buffer */ + buflen = strlen(SMB_ProtocolDialect)+2; /* include type and nul byte */ + SMB_ADDWORD(&buffer[len],buflen); len += 2; + + buffer[len] = 0x02; + strcpy(&buffer[len+1],SMB_ProtocolDialect); + len += buflen; + + if(!NB_Transaction(fd, buffer, len, &len)) + { + ERR("Failed\n"); + return FALSE; + } + + /* FIXME: check response */ + if(SMB_GetError(buffer)) + { + ERR("returned error\n"); + return FALSE; + } + + *dialect = 0; + + return TRUE; +} + +#define SMB_PARAM_COUNT(buffer) ((buffer)[SMB_PCOUNT]) +#define SMB_PARAM(buffer,n) SMB_GETWORD(&(buffer)[SMB_HDRSIZE+2*(n)]) +#define SMB_BUFFER_COUNT(buffer) SMB_GETWORD(buffer+SMB_HDRSIZE+2*SMB_PARAM_COUNT(buffer)) +#define SMB_BUFFER(buffer,n) ((buffer)[SMB_HDRSIZE + 2*SMB_PARAM_COUNT(buffer) + 2 + (n) ]) + +static BOOL SMB_SessionSetup(int fd, USHORT *userid) +{ + unsigned char buffer[0x100]; + int len = 0; + int i,pcount,bcount; + + memset(buffer,0,sizeof buffer); + + len = SMB_Header(buffer, SMB_COM_SESSION_SETUP_ANDX, 0, 0); + + buffer[len++] = 0; /* no parameters? */ + + buffer[len++] = 0xff; /* AndXCommand: secondary request */ + buffer[len++] = 0x00; /* AndXReserved */ + SMB_ADDWORD(&buffer[len],0); len += 2; /* AndXOffset */ + SMB_ADDWORD(&buffer[len],0x400); len += 2; /* MaxBufferSize */ + SMB_ADDWORD(&buffer[len],1); len += 2; /* MaxMpxCount */ + SMB_ADDWORD(&buffer[len],0); len += 2; /* VcNumber */ + SMB_ADDWORD(&buffer[len],0); len += 2; /* SessionKey */ + SMB_ADDWORD(&buffer[len],0); len += 2; /* SessionKey */ + SMB_ADDWORD(&buffer[len],0); len += 2; /* Password length */ + SMB_ADDWORD(&buffer[len],0); len += 2; /* Reserved */ + SMB_ADDWORD(&buffer[len],0); len += 2; /* Reserved */ + + /* FIXME: add name and password here */ + buffer[len++] = 0; /* number of bytes in password */ + + if(!NB_Transaction(fd, buffer, len, &len)) + return FALSE; + + if(SMB_GetError(buffer)) + return FALSE; + + pcount = SMB_PARAM_COUNT(buffer); + + if( (SMB_HDRSIZE+pcount*2) > len ) + { + ERR("Bad parameter count %d\n",pcount); + return FALSE; + } + + DPRINTF("SMB_COM_SESSION_SETUP response, %d args: ",pcount); + for(i=0; i<pcount; i++) + DPRINTF("%04x ",SMB_PARAM(buffer,i)); + DPRINTF("\n"); + + bcount = SMB_BUFFER_COUNT(buffer); + if( (SMB_HDRSIZE+pcount*2+2+bcount) > len ) + { + ERR("parameter count %x, buffer count %x, len %x\n",pcount,bcount,len); + return FALSE; + } + + DPRINTF("response buffer %d bytes: ",bcount); + for(i=0; i<bcount; i++) + { + unsigned char ch = SMB_BUFFER(buffer,i); + DPRINTF("%c", isprint(ch)?ch:' '); + } + DPRINTF("\n"); + + *userid = SMB_GETWORD(&buffer[SMB_USERID]); + + return TRUE; +} + +static BOOL SMB_TreeConnect(int fd, USHORT user_id, LPCSTR share_name, USHORT *treeid) +{ + unsigned char buffer[0x100]; + int len = 0,slen; + + ERR("%s\n",share_name); + + memset(buffer,0,sizeof buffer); + + len = SMB_Header(buffer, SMB_COM_TREE_CONNECT, 0, user_id); + + buffer[len++] = 4; /* parameters */ + + buffer[len++] = 0xff; /* AndXCommand: secondary request */ + buffer[len++] = 0x00; /* AndXReserved */ + SMB_ADDWORD(&buffer[len],0); len += 2; /* AndXOffset */ + SMB_ADDWORD(&buffer[len],0); len += 2; /* Flags */ + SMB_ADDWORD(&buffer[len],1); len += 2; /* Password length */ + + /* SMB command buffer */ + SMB_ADDWORD(&buffer[len],3); len += 2; /* command buffer len */ + buffer[len++] = 0; /* null terminated password */ + + slen = strlen(share_name); + if(slen<(sizeof buffer-len)) + strcpy(&buffer[len], share_name); + else + return FALSE; + len += slen+1; + + /* name of the service */ + buffer[len++] = 0; + + if(!NB_Transaction(fd, buffer, len, &len)) + return FALSE; + + if(SMB_GetError(buffer)) + return FALSE; + + *treeid = SMB_GETWORD(&buffer[SMB_TREEID]); + + ERR("OK, treeid = %04x\n", *treeid); + + return TRUE; +} + +static BOOL SMB_NtCreateOpen(int fd, USHORT tree_id, USHORT user_id, USHORT dialect, + LPCSTR filename, DWORD access, DWORD sharing, + LPSECURITY_ATTRIBUTES sa, DWORD creation, + DWORD attributes, HANDLE template, USHORT *file_id ) +{ + unsigned char buffer[0x100]; + int len = 0,slen; + + ERR("%s\n",filename); + + memset(buffer,0,sizeof buffer); + + len = SMB_Header(buffer, SMB_COM_NT_CREATE_ANDX, tree_id, user_id); + + /* 0 */ + buffer[len++] = 24; /* parameters */ + + buffer[len++] = 0xff; /* AndXCommand: secondary request */ + buffer[len++] = 0x00; /* AndXReserved */ + SMB_ADDWORD(&buffer[len],0); len += 2; /* AndXOffset */ + + buffer[len++] = 0; /* reserved */ + slen = strlen(filename); + SMB_ADDWORD(&buffer[len],slen); len += 2; /* name length */ + + /* 0x08 */ + SMB_ADDDWORD(&buffer[len],0); len += 4; /* flags */ + SMB_ADDDWORD(&buffer[len],0); len += 4; /* root directory fid */ + /* 0x10 */ + SMB_ADDDWORD(&buffer[len],access); len += 4; /* access */ + SMB_ADDDWORD(&buffer[len],0); len += 4; /* allocation size */ + /* 0x18 */ + SMB_ADDDWORD(&buffer[len],0); len += 4; /* root directory fid */ + + /* 0x1c */ + SMB_ADDDWORD(&buffer[len],0); len += 4; /* initial allocation */ + SMB_ADDDWORD(&buffer[len],0); len += 4; + + /* 0x24 */ + SMB_ADDDWORD(&buffer[len],attributes); len += 4; /* ExtFileAttributes*/ + + /* 0x28 */ + SMB_ADDDWORD(&buffer[len],sharing); len += 4; /* ShareAccess */ + + /* 0x2c */ + ERR("creation = %08lx\n",creation); + SMB_ADDDWORD(&buffer[len],creation); len += 4; /* CreateDisposition */ + + /* 0x30 */ + SMB_ADDDWORD(&buffer[len],creation); len += 4; /* CreateOptions */ + + /* 0x34 */ + SMB_ADDDWORD(&buffer[len],0); len += 4; /* Impersonation */ + + /* 0x38 */ + buffer[len++] = 0; /* security flags */ + + /* 0x39 */ + SMB_ADDWORD(&buffer[len],slen); len += 2; /* size of buffer */ + + if(slen<(sizeof buffer-len)) + strcpy(&buffer[len], filename); + else + return FALSE; + len += slen+1; + + /* name of the file */ + buffer[len++] = 0; + + if(!NB_Transaction(fd, buffer, len, &len)) + return FALSE; + + if(SMB_GetError(buffer)) + return FALSE; + + ERR("OK\n"); + + /* FIXME */ + /* *file_id = SMB_GETWORD(&buffer[xxx]); */ + *file_id = 0; + return FALSE; + + return TRUE; +} + +static USHORT SMB_GetMode(DWORD access, DWORD sharing) +{ + USHORT mode=0; + + switch(access&(GENERIC_READ|GENERIC_WRITE)) + { + case GENERIC_READ: + mode |= OF_READ; + break; + case GENERIC_WRITE: + mode |= OF_WRITE; + break; + case (GENERIC_READ|GENERIC_WRITE): + mode |= OF_READWRITE; + break; + } + + switch(sharing&(FILE_SHARE_READ|FILE_SHARE_WRITE)) + { + case (FILE_SHARE_READ|FILE_SHARE_WRITE): + mode |= OF_SHARE_DENY_NONE; + break; + case FILE_SHARE_READ: + mode |= OF_SHARE_DENY_WRITE; + break; + case FILE_SHARE_WRITE: + mode |= OF_SHARE_DENY_READ; + break; + default: + mode |= OF_SHARE_EXCLUSIVE; + break; + } + + return mode; +} + +/* inverse of FILE_ConvertOFMode */ +static BOOL SMB_OpenAndX(int fd, USHORT tree_id, USHORT user_id, USHORT dialect, + LPCSTR filename, DWORD access, DWORD sharing, + DWORD creation, DWORD attributes, USHORT *file_id ) +{ + unsigned char buffer[0x100]; + int len = 0; + USHORT mode; + + ERR("%s\n",filename); + + mode = SMB_GetMode(access,sharing); + + memset(buffer,0,sizeof buffer); + + len = SMB_Header(buffer, SMB_COM_OPEN_ANDX, tree_id, user_id); + + /* 0 */ + buffer[len++] = 15; /* parameters */ + buffer[len++] = 0xff; /* AndXCommand: secondary request */ + buffer[len++] = 0x00; /* AndXReserved */ + SMB_ADDWORD(buffer+len,0); len+=2; /* AndXOffset */ + SMB_ADDWORD(buffer+len,0); len+=2; /* Flags */ + SMB_ADDWORD(buffer+len,mode); len+=2; /* desired access */ + SMB_ADDWORD(buffer+len,0); len+=2; /* search attributes */ + SMB_ADDWORD(buffer+len,0); len+=2; + + /*FIXME: complete */ + return FALSE; +} + +static BOOL SMB_Open(int fd, USHORT tree_id, USHORT user_id, USHORT dialect, + LPCSTR filename, DWORD access, DWORD sharing, + DWORD creation, DWORD attributes, USHORT *file_id ) +{ + unsigned char buffer[0x100]; + int len = 0,slen,pcount,i; + USHORT mode = SMB_GetMode(access,sharing); + + ERR("%s\n",filename); + + memset(buffer,0,sizeof buffer); + + len = SMB_Header(buffer, SMB_COM_OPEN, tree_id, user_id); + + /* 0 */ + buffer[len++] = 2; /* parameters */ + SMB_ADDWORD(buffer+len,mode); len+=2; + SMB_ADDWORD(buffer+len,0); len+=2; /* search attributes */ + + slen = strlen(filename)+2; /* inc. nul and BufferFormat */ + SMB_ADDWORD(buffer+len,slen); len+=2; + + buffer[len] = 0x04; /* BufferFormat */ + strcpy(&buffer[len+1],filename); + len += slen; + + if(!NB_Transaction(fd, buffer, len, &len)) + return FALSE; + + if(SMB_GetError(buffer)) + return FALSE; + + pcount = SMB_PARAM_COUNT(buffer); + + if( (SMB_HDRSIZE+pcount*2) > len ) + { + ERR("Bad parameter count %d\n",pcount); + return FALSE; + } + + ERR("response, %d args: ",pcount); + for(i=0; i<pcount; i++) + DPRINTF("%04x ",SMB_PARAM(buffer,i)); + DPRINTF("\n"); + + *file_id = SMB_PARAM(buffer,0); + + ERR("file_id = %04x\n",*file_id); + + return TRUE; +} + +static BOOL SMB_Read(int fd, USHORT tree_id, USHORT user_id, USHORT dialect, USHORT file_id, DWORD offset, LPVOID out, USHORT count, LPUSHORT read) +{ + unsigned char *buffer; + int len,buf_size,n,i; + + ERR("user %04x tree %04x file %04x count %04x offset %08lx\n", + user_id, tree_id, file_id, count, offset); + + buf_size = count+0x100; + buffer = (unsigned char *) HeapAlloc(GetProcessHeap(),0,buf_size); + + memset(buffer,0,buf_size); + + len = SMB_Header(buffer, SMB_COM_READ, tree_id, user_id); + + buffer[len++] = 5; + SMB_ADDWORD(&buffer[len],file_id); len += 2; + SMB_ADDWORD(&buffer[len],count); len += 2; + SMB_ADDDWORD(&buffer[len],offset); len += 4; + SMB_ADDWORD(&buffer[len],0); len += 2; /* how many more bytes will be read */ + + buffer[len++] = 0; + + if(!NB_Transaction(fd, buffer, len, &len)) + { + HeapFree(GetProcessHeap(),0,buffer); + return FALSE; + } + + if(SMB_GetError(buffer)) + { + HeapFree(GetProcessHeap(),0,buffer); + return FALSE; + } + + n = SMB_PARAM_COUNT(buffer); + + if( (SMB_HDRSIZE+n*2) > len ) + { + HeapFree(GetProcessHeap(),0,buffer); + ERR("Bad parameter count %d\n",n); + return FALSE; + } + + ERR("response, %d args: ",n); + for(i=0; i<n; i++) + DPRINTF("%04x ",SMB_PARAM(buffer,i)); + DPRINTF("\n"); + + n = SMB_PARAM(buffer,5) - 3; + if(n>count) + n=count; + + memcpy( out, &SMB_BUFFER(buffer,3), n); + + ERR("Read %d bytes\n",n); + *read = n; + + HeapFree(GetProcessHeap(),0,buffer); + + return TRUE; +} + +static int SMB_LoginAndConnect(LPCSTR host, LPCSTR share, USHORT *tree_id, USHORT *user_id, USHORT *dialect) +{ + int fd=-1,r; + struct sockaddr_in sin; + LPSTR name=NULL; + + ERR("host %s share %s\n",host,share); + + /* FIXME: use various lookup methods */ + if(0) + NB_Lookup(host,&sin); + else + { + if(0==inet_aton("127.0.0.1", (struct in_addr *)&sin.sin_addr.s_addr)) + { + FIXME("Error getting localhost address\n"); + SetLastError( ERROR_PATH_NOT_FOUND ); + return INVALID_HANDLE_VALUE; + } + sin.sin_family = AF_INET; + sin.sin_port = htons(139); /* netbios session */ + } + + fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + if(fd<0) + goto fail; + + ERR("Connecting...\n"); + r = connect(fd, &sin, sizeof sin); + if(r<0) + goto fail; + + if(!NB_SessionReq(fd, "*SMBSERVER", "WINE")) + goto fail; + + if(!SMB_NegotiateProtocol(fd, dialect)) + goto fail; + + if(!SMB_SessionSetup(fd, user_id)) + goto fail; + + name = HeapAlloc(GetProcessHeap(),0,strlen(host)+strlen(share)+5); + if(!name) + goto fail; + sprintf(name,"\\\\%s\\%s",host,share); + if(!SMB_TreeConnect(fd,*user_id,name,tree_id)) + goto fail; + HeapFree(GetProcessHeap(),0,name); + + return fd; + +fail: + if(name) + HeapFree(GetProcessHeap(),0,name); + ERR("Failed\n"); + if(fd>=0) + close(fd); + return -1; +} + +static HANDLE SMB_RegisterFile( int fd, USHORT tree_id, USHORT user_id, USHORT dialect, USHORT file_id) +{ + int r; + HANDLE ret; + + wine_server_send_fd( fd ); + + SERVER_START_REQ( create_smb ) + { + req->tree_id = tree_id; + req->user_id = user_id; + req->file_id = file_id; + req->dialect = 0; + req->fd = fd; + SetLastError(0); + r = wine_server_call_err( req ); + ret = reply->handle; + } + SERVER_END_REQ; + + if(!r) + ERR("created wineserver smb object, handle = %04x\n",ret); + else + SetLastError( ERROR_PATH_NOT_FOUND ); + + return ret; +} + +HANDLE WINAPI SMB_CreateFileA( LPCSTR uncname, DWORD access, DWORD sharing, + LPSECURITY_ATTRIBUTES sa, DWORD creation, + DWORD attributes, HANDLE template ) +{ + int fd; + USHORT tree_id=0, user_id=0, dialect=0, file_id=0; + LPSTR name,host,share,file; + HANDLE handle = 0; + + name = HeapAlloc(GetProcessHeap(),0,lstrlenA(uncname)); + if(!name) + return -1; + + lstrcpyA(name,uncname); + + if( !UNC_SplitName(name, &host, &share, &file) ) + { + HeapFree(GetProcessHeap(),0,name); + return handle; + } + + ERR("server is %s, share is %s, file is %s\n", host, share, file); + fd = SMB_LoginAndConnect(host, share, &tree_id, &user_id, &dialect); + if(fd < 0) + { + HeapFree(GetProcessHeap(),0,name); + return handle; + } + +#if 0 + if(!SMB_NtCreateOpen(fd, tree_id, user_id, dialect, file, + access, sharing, sa, creation, attributes, template, &file_id )) + { + close(fd); + HeapFree(GetProcessHeap(),0,name); + ERR("CreateOpen failed\n"); + return handle; + } +#endif + if(!SMB_Open(fd, tree_id, user_id, dialect, file, + access, sharing, creation, attributes, &file_id )) + { + close(fd); + HeapFree(GetProcessHeap(),0,name); + ERR("CreateOpen failed\n"); + return handle; + } + + HeapFree(GetProcessHeap(),0,name); + + handle = SMB_RegisterFile(fd, tree_id, user_id, dialect, file_id); + if(!handle) + { + ERR("register failed\n"); + close(fd); + } + + return handle; +} + +static BOOL SMB_GetSmbInfo(HANDLE hFile, USHORT *tree_id, USHORT *user_id, USHORT *dialect, USHORT *file_id, LPDWORD offset) +{ + int r; + + SERVER_START_REQ( get_smb_info ) + { + req->handle = hFile; + req->flags = 0; + SetLastError(0); + r = wine_server_call_err( req ); + if(tree_id) + *tree_id = reply->tree_id; + if(user_id) + *user_id = reply->user_id; + if(file_id) + *file_id = reply->file_id; + if(dialect) + *dialect = reply->dialect; + if(offset) + *offset = reply->offset; + } + SERVER_END_REQ; + + return !r; +} + +static BOOL SMB_SetOffset(HANDLE hFile, DWORD offset) +{ + int r; + + ERR("offset = %08lx\n",offset); + + SERVER_START_REQ( get_smb_info ) + { + req->handle = hFile; + req->flags = SMBINFO_SET_OFFSET; + req->offset = offset; + SetLastError(0); + r = wine_server_call_err( req ); + /* if(offset) + *offset = reply->offset; */ + } + SERVER_END_REQ; + + return !r; +} + +WINAPI BOOL SMB_ReadFile(HANDLE hFile, LPVOID buffer, DWORD bytesToRead, LPDWORD bytesRead, LPOVERLAPPED lpOverlapped) +{ + int fd; + DWORD total, count, offset; + USHORT user_id, tree_id, dialect, file_id, read; + BOOL r=TRUE; + + ERR("%04x %p %ld %p\n", hFile, buffer, bytesToRead, bytesRead); + + if(!SMB_GetSmbInfo(hFile, &tree_id, &user_id, &dialect, &file_id, &offset)) + return FALSE; + + fd = FILE_GetUnixHandle(hFile, GENERIC_READ); + if(fd<0) + return FALSE; + + total = 0; + while(1) + { + count = bytesToRead - total; + if(count>0x400) + count = 0x400; + if(count==0) + break; + read = 0; + r = SMB_Read(fd, tree_id, user_id, dialect, file_id, offset, buffer, count, &read); + if(!r) + break; + if(!read) + break; + total += read; + buffer += read; + offset += read; + if(total>=bytesToRead) + break; + } + close(fd); + + if(bytesRead) + *bytesRead = total; + + if(!SMB_SetOffset(hFile, offset)) + return FALSE; + + return r; +} + diff --git a/files/smb.h b/files/smb.h new file mode 100644 index 00000000000..268261f6ee2 --- /dev/null +++ b/files/smb.h @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2002 Mike McCormack + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __INC_SMB__ +#define __INC_SMB__ + +#define NBR_ADDWORD(p,word) { (p)[1] = (word & 0xff); (p)[0] = ((word)>>8)&0xff; } +#define NBR_GETWORD(p) ( (((p)[0])<<8) | ((p)[1]) ) + +#define SMB_ADDWORD(p,word) { (p)[0] = (word & 0xff); (p)[1] = ((word)>>8)&0xff; } +#define SMB_GETWORD(p) ( (((p)[1])<<8) | ((p)[0]) ) +#define SMB_ADDDWORD(p,w) { (p)[3]=((w)>>24)&0xff; (p)[2]=((w)>>16)&0xff; (p)[1]=((w)>>8)&0xff; (p)[0]=(w)&0xff; } + +#define SMB_COM_CREATE_DIRECTORY 0x00 +#define SMB_COM_DELETE_DIRECTORY 0x01 +#define SMB_COM_OPEN 0x02 +#define SMB_COM_CREATE 0x03 +#define SMB_COM_CLOSE 0x04 +#define SMB_COM_FLUSH 0x05 +#define SMB_COM_DELETE 0x06 +#define SMB_COM_RENAME 0x07 +#define SMB_COM_QUERY_INFORMATION 0x08 +#define SMB_COM_SET_INFORMATION 0x09 +#define SMB_COM_READ 0x0A +#define SMB_COM_WRITE 0x0B +#define SMB_COM_LOCK_BYTE_RANGE 0x0C +#define SMB_COM_UNLOCK_BYTE_RANGE 0x0D +#define SMB_COM_CREATE_TEMPORARY 0x0E +#define SMB_COM_CREATE_NEW 0x0F +#define SMB_COM_CHECK_DIRECTORY 0x10 +#define SMB_COM_PROCESS_EXIT 0x11 +#define SMB_COM_SEEK 0x12 +#define SMB_COM_LOCK_AND_READ 0x13 +#define SMB_COM_WRITE_AND_UNLOCK 0x14 +#define SMB_COM_READ_RAW 0x1A +#define SMB_COM_READ_MPX 0x1B +#define SMB_COM_READ_MPX_SECONDARY 0x1C +#define SMB_COM_WRITE_RAW 0x1D +#define SMB_COM_WRITE_MPX 0x1E +#define SMB_COM_WRITE_COMPLETE 0x20 +#define SMB_COM_SET_INFORMATION2 0x22 +#define SMB_COM_QUERY_INFORMATION2 0x23 +#define SMB_COM_LOCKING_ANDX 0x24 +#define SMB_COM_TRANSACTION 0x25 +#define SMB_COM_TRANSACTION_SECONDARY 0x26 +#define SMB_COM_IOCTL 0x27 +#define SMB_COM_IOCTL_SECONDARY 0x28 +#define SMB_COM_COPY 0x29 +#define SMB_COM_MOVE 0x2A +#define SMB_COM_ECHO 0x2B +#define SMB_COM_WRITE_AND_CLOSE 0x2C +#define SMB_COM_OPEN_ANDX 0x2D +#define SMB_COM_READ_ANDX 0x2E +#define SMB_COM_WRITE_ANDX 0x2F +#define SMB_COM_CLOSE_AND_TREE_DISC 0x31 +#define SMB_COM_TRANSACTION2 0x32 +#define SMB_COM_TRANSACTION2_SECONDARY 0x33 +#define SMB_COM_FIND_CLOSE2 0x34 +#define SMB_COM_FIND_NOTIFY_CLOSE 0x35 +#define SMB_COM_TREE_CONNECT 0x70 +#define SMB_COM_TREE_DISCONNECT 0x71 +#define SMB_COM_NEGOTIATE 0x72 +#define SMB_COM_SESSION_SETUP_ANDX 0x73 +#define SMB_COM_LOGOFF_ANDX 0x74 +#define SMB_COM_TREE_CONNECT_ANDX 0x75 +#define SMB_COM_QUERY_INFORMATION_DISK 0x80 +#define SMB_COM_SEARCH 0x81 +#define SMB_COM_FIND 0x82 +#define SMB_COM_FIND_UNIQUE 0x83 +#define SMB_COM_NT_TRANSACT 0xA0 +#define SMB_COM_NT_TRANSACT_SECONDARY 0xA1 +#define SMB_COM_NT_CREATE_ANDX 0xA2 +#define SMB_COM_NT_CANCEL 0xA4 +#define SMB_COM_OPEN_PRINT_FILE 0xC0 +#define SMB_COM_WRITE_PRINT_FILE 0xC1 +#define SMB_COM_CLOSE_PRINT_FILE 0xC2 +#define SMB_COM_GET_PRINT_QUEUE 0xC3 + +extern WINAPI BOOL SMB_ReadFile(HANDLE hFile, LPVOID buffer, DWORD bytesToRead, LPDWORD bytesRead, LPOVERLAPPED lpOverlapped); +extern HANDLE WINAPI SMB_CreateFileA( LPCSTR filename, DWORD access, DWORD sharing, + LPSECURITY_ATTRIBUTES sa, DWORD creation, + DWORD attributes, HANDLE template ); + +#endif /* __INC_SMB__ */ + diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index 086de667bf3..eb54534726f 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -736,7 +736,8 @@ enum fd_type { FD_TYPE_INVALID, FD_TYPE_DEFAULT, - FD_TYPE_CONSOLE + FD_TYPE_CONSOLE, + FD_TYPE_SMB }; #define FD_FLAG_OVERLAPPED 0x01 #define FD_FLAG_TIMEOUT 0x02 @@ -2321,6 +2322,41 @@ struct get_named_pipe_info_reply }; +struct create_smb_request +{ + struct request_header __header; + int fd; + unsigned int tree_id; + unsigned int user_id; + unsigned int file_id; + unsigned int dialect; +}; +struct create_smb_reply +{ + struct reply_header __header; + handle_t handle; +}; + + +struct get_smb_info_request +{ + struct request_header __header; + handle_t handle; + unsigned int flags; + unsigned int offset; +}; +struct get_smb_info_reply +{ + struct reply_header __header; + unsigned int tree_id; + unsigned int user_id; + unsigned int dialect; + unsigned int file_id; + unsigned int offset; +}; +#define SMBINFO_SET_OFFSET 0x01 + + struct create_window_request { @@ -2742,6 +2778,8 @@ enum request REQ_wait_named_pipe, REQ_disconnect_named_pipe, REQ_get_named_pipe_info, + REQ_create_smb, + REQ_get_smb_info, REQ_create_window, REQ_link_window, REQ_destroy_window, @@ -2899,6 +2937,8 @@ union generic_request struct wait_named_pipe_request wait_named_pipe_request; struct disconnect_named_pipe_request disconnect_named_pipe_request; struct get_named_pipe_info_request get_named_pipe_info_request; + struct create_smb_request create_smb_request; + struct get_smb_info_request get_smb_info_request; struct create_window_request create_window_request; struct link_window_request link_window_request; struct destroy_window_request destroy_window_request; @@ -3054,6 +3094,8 @@ union generic_reply struct wait_named_pipe_reply wait_named_pipe_reply; struct disconnect_named_pipe_reply disconnect_named_pipe_reply; struct get_named_pipe_info_reply get_named_pipe_info_reply; + struct create_smb_reply create_smb_reply; + struct get_smb_info_reply get_smb_info_reply; struct create_window_reply create_window_reply; struct link_window_reply link_window_reply; struct destroy_window_reply destroy_window_reply; @@ -3075,6 +3117,6 @@ union generic_reply struct get_window_properties_reply get_window_properties_reply; }; -#define SERVER_PROTOCOL_VERSION 72 +#define SERVER_PROTOCOL_VERSION 73 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */ diff --git a/server/Makefile.in b/server/Makefile.in index 1bcfaaa3752..d62c3d954be 100644 --- a/server/Makefile.in +++ b/server/Makefile.in @@ -31,6 +31,7 @@ C_SRCS = \ select.c \ semaphore.c \ serial.c \ + smb.c \ snapshot.c \ sock.c \ thread.c \ diff --git a/server/protocol.def b/server/protocol.def index ad8292e2a5d..6cc06b5c51d 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -563,7 +563,8 @@ enum fd_type { FD_TYPE_INVALID, FD_TYPE_DEFAULT, - FD_TYPE_CONSOLE + FD_TYPE_CONSOLE, + FD_TYPE_SMB }; #define FD_FLAG_OVERLAPPED 0x01 #define FD_FLAG_TIMEOUT 0x02 @@ -1634,6 +1635,31 @@ enum message_type @END +@REQ(create_smb) + int fd; + unsigned int tree_id; + unsigned int user_id; + unsigned int file_id; + unsigned int dialect; +@REPLY + handle_t handle; +@END + + +@REQ(get_smb_info) + handle_t handle; + unsigned int flags; + unsigned int offset; +@REPLY + unsigned int tree_id; + unsigned int user_id; + unsigned int dialect; + unsigned int file_id; + unsigned int offset; +@END +#define SMBINFO_SET_OFFSET 0x01 + + /* Create a window */ @REQ(create_window) user_handle_t parent; /* parent window */ diff --git a/server/request.h b/server/request.h index 07aed4082b3..9a1350efbe9 100644 --- a/server/request.h +++ b/server/request.h @@ -232,6 +232,8 @@ DECL_HANDLER(connect_named_pipe); DECL_HANDLER(wait_named_pipe); DECL_HANDLER(disconnect_named_pipe); DECL_HANDLER(get_named_pipe_info); +DECL_HANDLER(create_smb); +DECL_HANDLER(get_smb_info); DECL_HANDLER(create_window); DECL_HANDLER(link_window); DECL_HANDLER(destroy_window); @@ -388,6 +390,8 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] = (req_handler)req_wait_named_pipe, (req_handler)req_disconnect_named_pipe, (req_handler)req_get_named_pipe_info, + (req_handler)req_create_smb, + (req_handler)req_get_smb_info, (req_handler)req_create_window, (req_handler)req_link_window, (req_handler)req_destroy_window, diff --git a/server/smb.c b/server/smb.c new file mode 100644 index 00000000000..ab0e84d2a77 --- /dev/null +++ b/server/smb.c @@ -0,0 +1,192 @@ +/* + * Server-side smb network file management + * + * Copyright (C) 1998 Alexandre Julliard + * Copyright (C) 2000, 2001, 2002 Mike McCormack + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * FIXME: if you can't find something to fix, + * you're not looking hard enough + */ + +#include "config.h" + +#include <assert.h> +#include <fcntl.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <errno.h> +#ifdef HAVE_SYS_ERRNO_H +#include <sys/errno.h> +#endif +#include <sys/time.h> +#include <sys/types.h> +#include <time.h> +#include <unistd.h> +#include <utime.h> +#include <termios.h> +#include <sys/ioctl.h> + +#include "winerror.h" +#include "winbase.h" + +#include "handle.h" +#include "thread.h" +#include "request.h" + +static void smb_dump( struct object *obj, int verbose ); +static int smb_get_fd( struct object *obj ); +static int smb_get_info( struct object *obj, struct get_file_info_reply *reply, int *flags ); +static int smb_get_poll_events( struct object *obj ); +static void destroy_smb(struct object *obj); + +struct smb +{ + struct object obj; + unsigned int tree_id; + unsigned int user_id; + unsigned int dialect; + unsigned int file_id; + unsigned int offset; +}; + +static const struct object_ops smb_ops = +{ + sizeof(struct smb), /* size */ + smb_dump, /* dump */ + default_poll_add_queue, /* add_queue */ + default_poll_remove_queue, /* remove_queue */ + default_poll_signaled, /* signaled */ + no_satisfied, /* satisfied */ + smb_get_poll_events, /* get_poll_events */ + default_poll_event, /* poll_event */ + smb_get_fd, /* get_fd */ + no_flush, /* flush */ + smb_get_info, /* get_file_info */ + NULL, /* queue_async */ + destroy_smb /* destroy */ +}; + +static void destroy_smb( struct object *obj) +{ + /* struct smb *smb = (struct smb *)obj; */ + assert( obj->ops == &smb_ops ); +} + +static void smb_dump( struct object *obj, int verbose ) +{ + struct smb *smb = (struct smb *)obj; + assert( obj->ops == &smb_ops ); + fprintf( stderr, "smb file with socket fd=%d \n", smb->obj.fd ); +} + +struct smb *get_smb_obj( struct process *process, handle_t handle, unsigned int access ) +{ + return (struct smb *)get_handle_obj( process, handle, access, &smb_ops ); +} + +static int smb_get_poll_events( struct object *obj ) +{ + /* struct smb *smb = (struct smb *)obj; */ + int events = 0; + assert( obj->ops == &smb_ops ); + + events |= POLLIN; + + /* fprintf(stderr,"poll events are %04x\n",events); */ + + return events; +} + +static int smb_get_fd( struct object *obj ) +{ + struct smb *smb = (struct smb *)obj; + assert( obj->ops == &smb_ops ); + return smb->obj.fd; +} + +static int smb_get_info( struct object *obj, struct get_file_info_reply *reply, int *flags ) +{ + /* struct smb *smb = (struct smb *) obj; */ + assert( obj->ops == &smb_ops ); + + if (reply) + { + reply->type = FILE_TYPE_CHAR; + reply->attr = 0; + reply->access_time = 0; + reply->write_time = 0; + reply->size_high = 0; + reply->size_low = 0; + reply->links = 0; + reply->index_high = 0; + reply->index_low = 0; + reply->serial = 0; + } + + *flags = 0; + + return FD_TYPE_SMB; +} + +/* create a smb */ +DECL_HANDLER(create_smb) +{ + struct smb *smb; + int fd; + + reply->handle = 0; + + fd = thread_get_inflight_fd( current, req->fd ); + if (fd == -1) + { + set_error( STATUS_INVALID_HANDLE ); + return; + } + + smb = alloc_object( &smb_ops, fd ); + if (smb) + { + smb->tree_id = req->tree_id; + smb->user_id = req->user_id; + smb->dialect = req->dialect; + smb->file_id = req->file_id; + smb->offset = 0; + reply->handle = alloc_handle( current->process, smb, GENERIC_READ, 0); + release_object( smb ); + } +} + +DECL_HANDLER(get_smb_info) +{ + struct smb *smb; + + if ((smb = get_smb_obj( current->process, req->handle, 0 ))) + { + if(req->flags & SMBINFO_SET_OFFSET) + smb->offset = req->offset; + + reply->tree_id = smb->tree_id; + reply->user_id = smb->user_id; + reply->dialect = smb->dialect; + reply->file_id = smb->file_id; + reply->offset = smb->offset; + + release_object( smb ); + } +} + diff --git a/server/trace.c b/server/trace.c index c4c2879ff1d..2e36fe4736f 100644 --- a/server/trace.c +++ b/server/trace.c @@ -1843,6 +1843,36 @@ static void dump_get_named_pipe_info_reply( const struct get_named_pipe_info_rep fprintf( stderr, " insize=%08x", req->insize ); } +static void dump_create_smb_request( const struct create_smb_request *req ) +{ + fprintf( stderr, " fd=%d,", req->fd ); + fprintf( stderr, " tree_id=%08x,", req->tree_id ); + fprintf( stderr, " user_id=%08x,", req->user_id ); + fprintf( stderr, " file_id=%08x,", req->file_id ); + fprintf( stderr, " dialect=%08x", req->dialect ); +} + +static void dump_create_smb_reply( const struct create_smb_reply *req ) +{ + fprintf( stderr, " handle=%d", req->handle ); +} + +static void dump_get_smb_info_request( const struct get_smb_info_request *req ) +{ + fprintf( stderr, " handle=%d,", req->handle ); + fprintf( stderr, " flags=%08x,", req->flags ); + fprintf( stderr, " offset=%08x", req->offset ); +} + +static void dump_get_smb_info_reply( const struct get_smb_info_reply *req ) +{ + fprintf( stderr, " tree_id=%08x,", req->tree_id ); + fprintf( stderr, " user_id=%08x,", req->user_id ); + fprintf( stderr, " dialect=%08x,", req->dialect ); + fprintf( stderr, " file_id=%08x,", req->file_id ); + fprintf( stderr, " offset=%08x", req->offset ); +} + static void dump_create_window_request( const struct create_window_request *req ) { fprintf( stderr, " parent=%08x,", req->parent ); @@ -2193,6 +2223,8 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = { (dump_func)dump_wait_named_pipe_request, (dump_func)dump_disconnect_named_pipe_request, (dump_func)dump_get_named_pipe_info_request, + (dump_func)dump_create_smb_request, + (dump_func)dump_get_smb_info_request, (dump_func)dump_create_window_request, (dump_func)dump_link_window_request, (dump_func)dump_destroy_window_request, @@ -2346,6 +2378,8 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = { (dump_func)0, (dump_func)0, (dump_func)dump_get_named_pipe_info_reply, + (dump_func)dump_create_smb_reply, + (dump_func)dump_get_smb_info_reply, (dump_func)dump_create_window_reply, (dump_func)dump_link_window_reply, (dump_func)0, @@ -2499,6 +2533,8 @@ static const char * const req_names[REQ_NB_REQUESTS] = { "wait_named_pipe", "disconnect_named_pipe", "get_named_pipe_info", + "create_smb", + "get_smb_info", "create_window", "link_window", "destroy_window", -- GitLab