summaryrefslogtreecommitdiffstats
path: root/source/smbd/reply.c
diff options
context:
space:
mode:
Diffstat (limited to 'source/smbd/reply.c')
-rw-r--r--source/smbd/reply.c4535
1 files changed, 2911 insertions, 1624 deletions
diff --git a/source/smbd/reply.c b/source/smbd/reply.c
index b7b51775bb8..397cae62217 100644
--- a/source/smbd/reply.c
+++ b/source/smbd/reply.c
@@ -1,8 +1,9 @@
+#define OLD_NTDOMAIN 1
/*
Unix SMB/Netbios implementation.
Version 1.9.
Main SMB reply routines
- Copyright (C) Andrew Tridgell 1992-1995
+ Copyright (C) Andrew Tridgell 1992-1998
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -25,222 +26,340 @@
#include "includes.h"
-#include "loadparm.h"
-#include "trans2.h"
/* look in server.c for some explanation of these variables */
extern int Protocol;
extern int DEBUGLEVEL;
-extern int chain_size;
-extern int maxxmit;
-extern int chain_fnum;
+extern int max_send;
+extern int max_recv;
extern char magic_char;
-extern connection_struct Connections[];
-extern files_struct Files[];
extern BOOL case_sensitive;
+extern BOOL case_preserve;
+extern BOOL short_case_preserve;
extern pstring sesssetup_user;
-extern int Client;
+extern pstring global_myname;
+extern fstring global_myworkgroup;
+extern int global_oplock_break;
+uint32 global_client_caps = 0;
+unsigned int smb_echo_count = 0;
-/* this macro should always be used to extract an fnum (smb_fid) from
-a packet to ensure chaining works correctly */
-#define GETFNUM(buf,where) (chain_fnum!= -1?chain_fnum:SVAL(buf,where))
+/****************************************************************************
+report a possible attack via the password buffer overflow bug
+****************************************************************************/
+
+static void overflow_attack(int len)
+{
+ if( DEBUGLVL( 0 ) ) {
+ dbgtext( "ERROR: Invalid password length %d.\n", len );
+ dbgtext( "Your machine may be under attack by someone " );
+ dbgtext( "attempting to exploit an old bug.\n" );
+ dbgtext( "Attack was from IP = %s.\n", client_addr() );
+ }
+ exit_server("possible attack");
+}
/****************************************************************************
reply to an special message
****************************************************************************/
+
int reply_special(char *inbuf,char *outbuf)
{
- int outsize = 4;
- int msg_type = CVAL(inbuf,0);
- int msg_flags = CVAL(inbuf,1);
- pstring name1,name2;
- extern fstring remote_machine;
- extern fstring local_machine;
- char *p;
+ int outsize = 4;
+ int msg_type = CVAL(inbuf,0);
+ int msg_flags = CVAL(inbuf,1);
+ pstring name1,name2;
+ extern fstring remote_machine;
+ extern fstring local_machine;
+ int len;
+ char name_type = 0;
+
+ *name1 = *name2 = 0;
+
+ memset(outbuf,'\0',smb_size);
+
+ smb_setlen(outbuf,0);
+
+ switch (msg_type) {
+ case 0x81: /* session request */
+ CVAL(outbuf,0) = 0x82;
+ CVAL(outbuf,3) = 0;
+ if (name_len(inbuf+4) > 50 ||
+ name_len(inbuf+4 + name_len(inbuf + 4)) > 50) {
+ DEBUG(0,("Invalid name length in session request\n"));
+ return(0);
+ }
+ name_extract(inbuf,4,name1);
+ name_extract(inbuf,4 + name_len(inbuf + 4),name2);
+ DEBUG(2,("netbios connect: name1=%s name2=%s\n",
+ name1,name2));
+
+ fstrcpy(remote_machine,name2);
+ remote_machine[15] = 0;
+ trim_string(remote_machine," "," ");
+ strlower(remote_machine);
+
+ fstrcpy(local_machine,name1);
+ len = strlen(local_machine);
+ if (len == 16) {
+ name_type = local_machine[15];
+ local_machine[15] = 0;
+ }
+ trim_string(local_machine," "," ");
+ strlower(local_machine);
+
+ if (name_type == 'R') {
+ /* We are being asked for a pathworks session ---
+ no thanks! */
+ CVAL(outbuf, 0) = 0x83;
+ break;
+ }
- *name1 = *name2 = 0;
+ add_session_user(remote_machine);
- smb_setlen(outbuf,0);
+ reload_services(True);
+ reopen_logs();
- switch (msg_type)
- {
- case 0x81: /* session request */
- CVAL(outbuf,0) = 0x82;
- CVAL(outbuf,3) = 0;
- if (name_len(inbuf+4) > 50)
- {
- DEBUG(0,("Invalid name length in session request\n"));
- return(0);
+ if (lp_status(-1)) {
+ claim_connection(NULL,"",MAXSTATUS,True);
+ }
+
+ break;
+
+ case 0x89: /* session keepalive request
+ (some old clients produce this?) */
+ CVAL(outbuf,0) = 0x85;
+ CVAL(outbuf,3) = 0;
+ break;
+
+ case 0x82: /* positive session response */
+ case 0x83: /* negative session response */
+ case 0x84: /* retarget session response */
+ DEBUG(0,("Unexpected session response\n"));
+ break;
+
+ case 0x85: /* session keepalive */
+ default:
+ return(0);
}
- name_extract(inbuf,4,name1);
- name_extract(inbuf,4 + name_len(inbuf + 4),name2);
- DEBUG(2,("netbios connect: name1=%s name2=%s\n",name1,name2));
+
+ DEBUG(5,("init msg_type=0x%x msg_flags=0x%x\n",
+ msg_type, msg_flags));
+
+ return(outsize);
+}
- strcpy(remote_machine,name2);
- trim_string(remote_machine," "," ");
- p = strchr(remote_machine,' ');
- strlower(remote_machine);
- if (p) *p = 0;
- strcpy(local_machine,name1);
- trim_string(local_machine," "," ");
- p = strchr(local_machine,' ');
- strlower(local_machine);
- if (p) *p = 0;
+/*******************************************************************
+work out what error to give to a failed connection
+********************************************************************/
- add_session_user(remote_machine);
+static int connection_error(char *inbuf,char *outbuf,int ecode)
+{
+ if (ecode == ERRnoipc || ecode == ERRnosuchshare)
+ return(ERROR(ERRDOS,ecode));
- reload_services(True);
- reopen_logs();
+ return(ERROR(ERRSRV,ecode));
+}
- break;
- case 0x85: /* session keepalive */
- default:
- return(0);
- }
+
+
+/****************************************************************************
+ parse a share descriptor string
+****************************************************************************/
+static void parse_connect(char *p,char *service,char *user,
+ char *password,int *pwlen,char *dev)
+{
+ char *p2;
+
+ DEBUG(4,("parsing connect string %s\n",p));
+
+ p2 = strrchr(p,'\\');
+ if (p2 == NULL)
+ fstrcpy(service,p);
+ else
+ fstrcpy(service,p2+1);
- DEBUG(5,("%s init msg_type=0x%x msg_flags=0x%x\n",timestring(),msg_type,msg_flags));
+ p += strlen(p) + 2;
- return(outsize);
-}
+ fstrcpy(password,p);
+ *pwlen = strlen(password);
+ p += strlen(p) + 2;
-/*******************************************************************
-work out what error to give to a failed connection
-********************************************************************/
-static int connection_error(char *inbuf,char *outbuf,int connection_num)
-{
- switch (connection_num)
+ fstrcpy(dev,p);
+
+ *user = 0;
+ p = strchr(service,'%');
+ if (p != NULL)
{
- case -8:
- return(ERROR(ERRSRV,ERRnoresource));
- case -7:
- return(ERROR(ERRSRV,ERRbaduid));
- case -6:
- return(ERROR(ERRSRV,ERRinvdevice));
- case -5:
- return(ERROR(ERRSRV,ERRinvnetname));
- case -4:
- return(ERROR(ERRSRV,ERRaccess));
- case -3:
- return(ERROR(ERRDOS,ERRnoipc));
- case -2:
- return(ERROR(ERRSRV,ERRinvnetname));
+ *p = 0;
+ fstrcpy(user,p+1);
}
- return(ERROR(ERRSRV,ERRbadpw));
}
-
/****************************************************************************
- reply to a tcon
+ Reply to a tcon.
****************************************************************************/
-int reply_tcon(char *inbuf,char *outbuf)
+
+int reply_tcon(connection_struct *conn,
+ char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
{
- pstring service;
- pstring user;
- pstring password;
- pstring dev;
- int connection_num;
- int outsize = 0;
- int uid = SVAL(inbuf,smb_uid);
- int vuid;
- int pwlen;
+ BOOL doencrypt = SMBENCRYPT();
+ pstring service;
+ pstring user;
+ pstring password;
+ pstring dev;
+ int outsize = 0;
+ uint16 vuid = SVAL(inbuf,smb_uid);
+ int pwlen=0;
+ int ecode = -1;
+
+ *service = *user = *password = *dev = 0;
+
+ parse_connect(smb_buf(inbuf)+1,service,user,password,&pwlen,dev);
+
+ /*
+ * Ensure the user and password names are in UNIX codepage format.
+ */
- *service = *user = *password = *dev = 0;
+ dos_to_unix(user,True);
+ if (!doencrypt)
+ dos_to_unix(password,True);
- vuid = valid_uid(uid);
-
- parse_connect(inbuf,service,user,password,&pwlen,dev);
+ /*
+ * Pass the user through the NT -> unix user mapping
+ * function.
+ */
+
+ (void)map_username(user);
+
+ /*
+ * Do any UNIX username case mangling.
+ */
+ (void)Get_Pwnam( user, True);
- connection_num = make_connection(service,user,password,pwlen,dev,vuid);
+ conn = make_connection(service,user,password,pwlen,dev,vuid,&ecode);
- if (connection_num < 0)
- return(connection_error(inbuf,outbuf,connection_num));
+ if (!conn) {
+ return(connection_error(inbuf,outbuf,ecode));
+ }
- outsize = set_message(outbuf,2,0,True);
- SSVAL(outbuf,smb_vwv0,maxxmit);
- SSVAL(outbuf,smb_vwv1,connection_num);
- SSVAL(outbuf,smb_tid,connection_num);
+ outsize = set_message(outbuf,2,0,True);
+ SSVAL(outbuf,smb_vwv0,max_recv);
+ SSVAL(outbuf,smb_vwv1,conn->cnum);
+ SSVAL(outbuf,smb_tid,conn->cnum);
- DEBUG(3,("%s tcon service=%s user=%s cnum=%d\n",timestring(),service,user,connection_num));
+ DEBUG(3,("tcon service=%s user=%s cnum=%d\n",
+ service, user, conn->cnum));
- return(outsize);
+ return(outsize);
}
-
/****************************************************************************
- reply to a tcon and X
+ Reply to a tcon and X.
****************************************************************************/
-int reply_tcon_and_X(char *inbuf,char *outbuf,int length,int bufsize)
+int reply_tcon_and_X(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
{
- pstring service;
- pstring user;
- pstring password;
- pstring devicename;
- int connection_num;
- int outsize = 0;
- int uid = SVAL(inbuf,smb_uid);
- int vuid;
- int smb_com2 = SVAL(inbuf,smb_vwv0);
- int smb_off2 = SVAL(inbuf,smb_vwv1);
- int passlen = SVAL(inbuf,smb_vwv3);
-
- *service = *user = *password = *devicename = 0;
+ fstring service;
+ pstring user;
+ pstring password;
+ pstring devicename;
+ BOOL doencrypt = SMBENCRYPT();
+ int ecode = -1;
+ uint16 vuid = SVAL(inbuf,smb_uid);
+ int passlen = SVAL(inbuf,smb_vwv3);
+ char *path;
+ char *p;
+
+ *service = *user = *password = *devicename = 0;
- /* we might have to close an old one */
- if ((SVAL(inbuf,smb_vwv2) & 0x1) != 0)
- close_cnum(SVAL(inbuf,smb_tid),uid);
-
- vuid = valid_uid(uid);
-
- {
- char *path;
- char *p;
- memcpy(password,smb_buf(inbuf),passlen);
- password[passlen]=0;
- path = smb_buf(inbuf) + passlen;
- DEBUG(4,("parsing net-path %s, passlen=%d\n",path,passlen));
- strcpy(service,path+2);
- p = strchr(service,'\\');
- if (!p)
- return(ERROR(ERRSRV,ERRinvnetname));
- *p = 0;
- strcpy(service,p+1);
- p = strchr(service,'%');
- if (p)
- {
- *p++ = 0;
- strcpy(user,p);
- }
- StrnCpy(devicename,path + strlen(path) + 1,6);
- DEBUG(4,("Got device type %s\n",devicename));
- }
+ /* we might have to close an old one */
+ if ((SVAL(inbuf,smb_vwv2) & 0x1) && conn) {
+ close_cnum(conn,vuid);
+ }
- connection_num = make_connection(service,user,password,passlen,devicename,vuid);
-
- if (connection_num < 0)
- return(connection_error(inbuf,outbuf,connection_num));
+ if (passlen > MAX_PASS_LEN) {
+ overflow_attack(passlen);
+ }
+
+ memcpy(password,smb_buf(inbuf),passlen);
+ password[passlen]=0;
+ path = smb_buf(inbuf) + passlen;
+
+ if (passlen != 24) {
+ if (strequal(password," "))
+ *password = 0;
+ passlen = strlen(password);
+ }
+
+ p = strchr(path+2,'\\');
+ if (!p)
+ return(ERROR(ERRDOS,ERRnosuchshare));
+ fstrcpy(service,p+1);
+ p = strchr(service,'%');
+ if (p) {
+ *p++ = 0;
+ fstrcpy(user,p);
+ }
+ StrnCpy(devicename,path + strlen(path) + 1,6);
+ DEBUG(4,("Got device type %s\n",devicename));
- outsize = set_message(outbuf,2,strlen(devicename)+1,True);
-
- DEBUG(3,("%s tconX service=%s user=%s cnum=%d\n",timestring(),service,user,connection_num));
-
- /* set the incoming and outgoing tid to the just created one */
- SSVAL(inbuf,smb_tid,connection_num);
- SSVAL(outbuf,smb_tid,connection_num);
+ /*
+ * Ensure the user and password names are in UNIX codepage format.
+ */
- CVAL(outbuf,smb_vwv0) = smb_com2;
- SSVAL(outbuf,smb_vwv1,(chain_size + outsize)-4);
+ dos_to_unix(user,True);
+ if (!doencrypt)
+ dos_to_unix(password,True);
- strcpy(smb_buf(outbuf),devicename);
+ /*
+ * Pass the user through the NT -> unix user mapping
+ * function.
+ */
+
+ (void)map_username(user);
+
+ /*
+ * Do any UNIX username case mangling.
+ */
+ (void)Get_Pwnam(user, True);
+
+ conn = make_connection(service,user,password,passlen,devicename,vuid,&ecode);
+
+ if (!conn)
+ return(connection_error(inbuf,outbuf,ecode));
+
+ if (Protocol < PROTOCOL_NT1) {
+ set_message(outbuf,2,strlen(devicename)+1,True);
+ pstrcpy(smb_buf(outbuf),devicename);
+ } else {
+ char *fsname = lp_fstype(SNUM(conn));
+
+ set_message(outbuf,3,3,True);
+
+ p = smb_buf(outbuf);
+ pstrcpy(p,devicename); p = skip_string(p,1); /* device name */
+ pstrcpy(p,fsname); p = skip_string(p,1); /* filesystem type e.g NTFS */
+
+ set_message(outbuf,3,PTR_DIFF(p,smb_buf(outbuf)),False);
+
+ /* what does setting this bit do? It is set by NT4 and
+ may affect the ability to autorun mounted cdroms */
+ SSVAL(outbuf, smb_vwv2, SMB_SUPPORT_SEARCH_BITS);
+
+ init_dfsroot(conn, inbuf, outbuf);
+ }
- if (smb_com2 != 0xFF)
- outsize += chain_reply(smb_com2,inbuf,inbuf+smb_off2+4,
- outbuf,outbuf+outsize,
- length,bufsize);
+
+ DEBUG(3,("tconX service=%s user=%s\n",
+ service, user));
+
+ /* set the incoming and outgoing tid to the just created one */
+ SSVAL(inbuf,smb_tid,conn->cnum);
+ SSVAL(outbuf,smb_tid,conn->cnum);
- return(outsize);
+ return chain_reply(inbuf,outbuf,length,bufsize);
}
@@ -249,179 +368,603 @@ int reply_tcon_and_X(char *inbuf,char *outbuf,int length,int bufsize)
****************************************************************************/
int reply_unknown(char *inbuf,char *outbuf)
{
- int cnum;
- int type;
- cnum = SVAL(inbuf,smb_tid);
- type = CVAL(inbuf,smb_com);
+ int type;
+ type = CVAL(inbuf,smb_com);
- DEBUG(0,("%s unknown command type (%s): cnum=%d type=%d (0x%X)\n",
- timestring(),
- smb_fn_name(type),
- cnum,type,type));
+ DEBUG(0,("unknown command type (%s): type=%d (0x%X)\n",
+ smb_fn_name(type), type, type));
- return(ERROR(ERRSRV,ERRunknownsmb));
+ return(ERROR(ERRSRV,ERRunknownsmb));
}
/****************************************************************************
reply to an ioctl
****************************************************************************/
-int reply_ioctl(char *inbuf,char *outbuf)
+int reply_ioctl(connection_struct *conn,
+ char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
{
- DEBUG(3,("ignoring ioctl\n"));
-
- return(ERROR(ERRSRV,ERRnosupport));
+ uint16 device = SVAL(inbuf,smb_vwv1);
+ uint16 function = SVAL(inbuf,smb_vwv2);
+ uint32 ioctl_code = (device << 16) + function;
+ int replysize, outsize;
+ char *p;
+ files_struct *fsp = file_fsp(inbuf,smb_vwv0);
+
+ DEBUG(4, ("Received IOCTL (code 0x%x)\n", ioctl_code));
+
+ switch (ioctl_code)
+ {
+ case IOCTL_QUERY_JOB_INFO:
+ replysize = 32;
+ break;
+ default:
+ return(ERROR(ERRSRV,ERRnosupport));
+ }
+
+ outsize = set_message(outbuf,8,replysize+1,True);
+ SSVAL(outbuf,smb_vwv1,replysize); /* Total data bytes returned */
+ SSVAL(outbuf,smb_vwv5,replysize); /* Data bytes this buffer */
+ SSVAL(outbuf,smb_vwv6,52); /* Offset to data */
+ p = smb_buf(outbuf) + 1; /* Allow for alignment */
+
+ switch (ioctl_code)
+ {
+ case IOCTL_QUERY_JOB_INFO:
+ SSVAL(p,0,fsp->print_jobid); /* Job number */
+ StrnCpy(p+2, global_myname, 15); /* Our NetBIOS name */
+ StrnCpy(p+18, lp_servicename(SNUM(conn)), 13); /* Service name */
+ break;
+ }
+
+ return outsize;
}
+/****************************************************************************
+ always return an error: it's just a matter of which one...
+ ****************************************************************************/
+static int session_trust_account(connection_struct *conn, char *inbuf, char *outbuf, char *user,
+ char *smb_passwd, int smb_passlen,
+ char *smb_nt_passwd, int smb_nt_passlen)
+{
+ struct smb_passwd *smb_trust_acct = NULL; /* check if trust account exists */
+ if (lp_security() == SEC_USER) {
+ smb_trust_acct = getsmbpwnam(user);
+ } else {
+ DEBUG(0,("session_trust_account: Trust account %s only supported with security = user\n", user));
+ SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
+ return(ERROR(0, NT_STATUS_LOGON_FAILURE));
+ }
+
+ if (smb_trust_acct == NULL) {
+ /* lkclXXXX: workstation entry doesn't exist */
+ DEBUG(0,("session_trust_account: Trust account %s user doesn't exist\n",user));
+ SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
+ return(ERROR(0, NT_STATUS_NO_SUCH_USER));
+ } else {
+ if ((smb_passlen != 24) || (smb_nt_passlen != 24)) {
+ DEBUG(0,("session_trust_account: Trust account %s - password length wrong.\n", user));
+ SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
+ return(ERROR(0, NT_STATUS_LOGON_FAILURE));
+ }
+
+ if (!smb_password_ok(smb_trust_acct, NULL, (unsigned char *)smb_passwd, (unsigned char *)smb_nt_passwd)) {
+ DEBUG(0,("session_trust_account: Trust Account %s - password failed\n", user));
+ SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
+ return(ERROR(0, NT_STATUS_LOGON_FAILURE));
+ }
+
+ if (smb_trust_acct->acct_ctrl & ACB_DOMTRUST) {
+ DEBUG(0,("session_trust_account: Domain trust account %s denied by server\n",user));
+ SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
+ return(ERROR(0, NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT));
+ }
+
+ if (smb_trust_acct->acct_ctrl & ACB_SVRTRUST) {
+ DEBUG(0,("session_trust_account: Server trust account %s denied by server\n",user));
+ SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
+ return(ERROR(0, NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT));
+ }
+
+ if (smb_trust_acct->acct_ctrl & ACB_WSTRUST) {
+ DEBUG(4,("session_trust_account: Wksta trust account %s denied by server\n", user));
+ SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
+ return(ERROR(0, NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT));
+ }
+ }
+
+ /* don't know what to do: indicate logon failure */
+ SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
+ return(ERROR(0, NT_STATUS_LOGON_FAILURE));
+}
+
+/****************************************************************************
+ Create a UNIX user on demand.
+****************************************************************************/
+
+static int smb_create_user(char *unix_user)
+{
+ pstring add_script;
+ int ret;
+
+ pstrcpy(add_script, lp_adduser_script());
+ if (! *add_script) return -1;
+ pstring_sub(add_script, "%u", unix_user);
+ ret = smbrun(add_script,NULL,False);
+ DEBUG(3,("smb_create_user: Running the command `%s' gave %d\n",add_script,ret));
+ return ret;
+}
+
+/****************************************************************************
+ Delete a UNIX user on demand.
+****************************************************************************/
+
+static int smb_delete_user(char *unix_user)
+{
+ pstring del_script;
+ int ret;
+
+ pstrcpy(del_script, lp_deluser_script());
+ if (! *del_script) return -1;
+ pstring_sub(del_script, "%u", unix_user);
+ ret = smbrun(del_script,NULL,False);
+ DEBUG(3,("smb_delete_user: Running the command `%s' gave %d\n",del_script,ret));
+ return ret;
+}
+
+/****************************************************************************
+ Check user is in correct domain if required
+****************************************************************************/
+
+static BOOL check_domain_match(char *user, char *domain)
+{
+ /*
+ * If we aren't serving to trusted domains, we must make sure that
+ * the validation request comes from an account in the same domain
+ * as the Samba server
+ */
+
+ if (!lp_allow_trusted_domains() &&
+ !strequal(lp_workgroup(), domain) ) {
+ DEBUG(1, ("check_domain_match: Attempt to connect as user %s from domain %s denied.\n", user, domain));
+ return False;
+ } else {
+ return True;
+ }
+}
+
+/****************************************************************************
+ Check for a valid username and password in security=server mode.
+****************************************************************************/
+
+static BOOL check_server_security(char *orig_user, char *domain, char *unix_user,
+ char *smb_apasswd, int smb_apasslen,
+ char *smb_ntpasswd, int smb_ntpasslen)
+{
+ BOOL ret = False;
+
+ if(lp_security() != SEC_SERVER)
+ return False;
+
+ if (!check_domain_match(orig_user, domain))
+ return False;
+
+ ret = server_validate(orig_user, domain,
+ smb_apasswd, smb_apasslen,
+ smb_ntpasswd, smb_ntpasslen);
+ if(ret) {
+ /*
+ * User validated ok against Domain controller.
+ * If the admin wants us to try and create a UNIX
+ * user on the fly, do so.
+ * Note that we can never delete users when in server
+ * level security as we never know if it was a failure
+ * due to a bad password, or the user really doesn't exist.
+ */
+ if(lp_adduser_script() && !smb_getpwnam(unix_user,True)) {
+ smb_create_user(unix_user);
+ }
+ }
+
+ return ret;
+}
+
+/****************************************************************************
+ Check for a valid username and password in security=domain mode.
+****************************************************************************/
+
+static BOOL check_domain_security(char *orig_user, char *domain, char *unix_user,
+ char *smb_apasswd, int smb_apasslen,
+ char *smb_ntpasswd, int smb_ntpasslen)
+{
+ BOOL ret = False;
+ BOOL user_exists = True;
+
+ if(lp_security() != SEC_DOMAIN)
+ return False;
+
+ if (!check_domain_match(orig_user, domain))
+ return False;
+
+ ret = domain_client_validate(orig_user, domain,
+ smb_apasswd, smb_apasslen,
+ smb_ntpasswd, smb_ntpasslen,
+ &user_exists);
+
+ if(ret) {
+ /*
+ * User validated ok against Domain controller.
+ * If the admin wants us to try and create a UNIX
+ * user on the fly, do so.
+ */
+ if(user_exists && lp_adduser_script() && !smb_getpwnam(unix_user,True)) {
+ smb_create_user(unix_user);
+ }
+ } else {
+ /*
+ * User failed to validate ok against Domain controller.
+ * If the failure was "user doesn't exist" and admin
+ * wants us to try and delete that UNIX user on the fly,
+ * do so.
+ */
+ if(!user_exists && lp_deluser_script() && smb_getpwnam(unix_user,True)) {
+ smb_delete_user(unix_user);
+ }
+ }
+
+ return ret;
+}
+
+/****************************************************************************
+ Return a bad password error configured for the correct client type.
+****************************************************************************/
+
+static int bad_password_error(char *inbuf,char *outbuf)
+{
+ enum remote_arch_types ra_type = get_remote_arch();
+
+ if(((ra_type == RA_WINNT) || (ra_type == RA_WIN2K)) &&
+ (global_client_caps & (CAP_NT_SMBS | CAP_STATUS32 ))) {
+ SSVAL(outbuf,smb_flg2,FLAGS2_32_BIT_ERROR_CODES);
+ return(ERROR(0,NT_STATUS_LOGON_FAILURE));
+ }
+
+ return(ERROR(ERRSRV,ERRbadpw));
+}
/****************************************************************************
reply to a session setup command
****************************************************************************/
-int reply_sesssetup_and_X(char *inbuf,char *outbuf,int length,int bufsize)
+
+int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
{
- int outsize = 0;
- int sess_uid;
- int gid;
- int smb_com2;
- int smb_off2;
+ uint16 sess_vuid;
+ gid_t gid;
+ uid_t uid;
int smb_bufsize;
- int smb_mpxmax;
- int smb_vc_num;
- uint32 smb_sesskey;
- int smb_apasslen;
+ int smb_apasslen = 0;
pstring smb_apasswd;
int smb_ntpasslen = 0;
pstring smb_ntpasswd;
BOOL valid_nt_password = False;
pstring user;
+ pstring orig_user;
BOOL guest=False;
+ static BOOL done_sesssetup = False;
+ BOOL doencrypt = SMBENCRYPT();
+ char *domain = "";
*smb_apasswd = 0;
+ *smb_ntpasswd = 0;
- sess_uid = SVAL(inbuf,smb_uid);
- smb_com2 = CVAL(inbuf,smb_vwv0);
- smb_off2 = SVAL(inbuf,smb_vwv1);
smb_bufsize = SVAL(inbuf,smb_vwv2);
- smb_mpxmax = SVAL(inbuf,smb_vwv3);
- smb_vc_num = SVAL(inbuf,smb_vwv4);
- smb_sesskey = IVAL(inbuf,smb_vwv5);
if (Protocol < PROTOCOL_NT1) {
smb_apasslen = SVAL(inbuf,smb_vwv7);
+ if (smb_apasslen > MAX_PASS_LEN)
+ overflow_attack(smb_apasslen);
+
memcpy(smb_apasswd,smb_buf(inbuf),smb_apasslen);
- StrnCpy(user,smb_buf(inbuf)+smb_apasslen,sizeof(user)-1);
+ smb_apasswd[smb_apasslen] = 0;
+ pstrcpy(user,smb_buf(inbuf)+smb_apasslen);
+ /*
+ * Incoming user is in DOS codepage format. Convert
+ * to UNIX.
+ */
+ dos_to_unix(user,True);
+
+ if (!doencrypt && (lp_security() != SEC_SERVER)) {
+ smb_apasslen = strlen(smb_apasswd);
+ }
} else {
uint16 passlen1 = SVAL(inbuf,smb_vwv7);
uint16 passlen2 = SVAL(inbuf,smb_vwv8);
- BOOL doencrypt = SMBENCRYPT();
- char *p = smb_buf(inbuf);
- if (passlen1 > 256) passlen1 = 0;
- if (passlen2 > 256) passlen2 = 0; /* I don't know why NT gives weird
- lengths sometimes */
- if(doencrypt) {
+ enum remote_arch_types ra_type = get_remote_arch();
+ char *p = smb_buf(inbuf);
+
+ if(global_client_caps == 0)
+ global_client_caps = IVAL(inbuf,smb_vwv11);
+
+ /* client_caps is used as final determination if client is NT or Win95.
+ This is needed to return the correct error codes in some
+ circumstances.
+ */
+
+ if(ra_type == RA_WINNT || ra_type == RA_WIN2K || ra_type == RA_WIN95) {
+ if(!(global_client_caps & (CAP_NT_SMBS | CAP_STATUS32))) {
+ set_remote_arch( RA_WIN95);
+ }
+ }
+
+ if (passlen1 != 24 && passlen2 != 24)
+ doencrypt = False;
+
+ if (passlen1 > MAX_PASS_LEN) {
+ overflow_attack(passlen1);
+ }
+
+ passlen1 = MIN(passlen1, MAX_PASS_LEN);
+ passlen2 = MIN(passlen2, MAX_PASS_LEN);
+
+ if(!doencrypt) {
+ /* both Win95 and WinNT stuff up the password lengths for
+ non-encrypting systems. Uggh.
+
+ if passlen1==24 its a win95 system, and its setting the
+ password length incorrectly. Luckily it still works with the
+ default code because Win95 will null terminate the password
+ anyway
+
+ if passlen1>0 and passlen2>0 then maybe its a NT box and its
+ setting passlen2 to some random value which really stuffs
+ things up. we need to fix that one. */
+
+ if (passlen1 > 0 && passlen2 > 0 && passlen2 != 24 && passlen2 != 1)
+ passlen2 = 0;
+ }
+
+ if (lp_restrict_anonymous()) {
+ /* there seems to be no reason behind the differences in MS clients formatting
+ * various info like the domain, NativeOS, and NativeLanMan fields. Win95
+ * in particular seems to have an extra null byte between the username and the
+ * domain, or the password length calculation is wrong, which throws off the
+ * string extraction routines below. This makes the value of domain be the
+ * empty string, which fails the restrict anonymous check further down.
+ * This compensates for that, and allows browsing to work in mixed NT and
+ * win95 environments even when restrict anonymous is true. AAB
+ */
+ dump_data(100, p, 0x70);
+ DEBUG(9, ("passlen1=%d, passlen2=%d\n", passlen1, passlen2));
+ if (ra_type == RA_WIN95 && !passlen1 && !passlen2 && p[0] == 0 && p[1] == 0) {
+ DEBUG(0, ("restrict anonymous parameter used in a win95 environment!\n"));
+ DEBUG(0, ("client is win95 and broken passlen1 offset -- attempting fix\n"));
+ DEBUG(0, ("if win95 cilents are having difficulty browsing, you will be unable to use restrict anonymous\n"));
+ passlen1 = 1;
+ }
+ }
+
+ if(doencrypt || ((lp_security() == SEC_SERVER) || (lp_security() == SEC_DOMAIN))) {
/* Save the lanman2 password and the NT md4 password. */
smb_apasslen = passlen1;
memcpy(smb_apasswd,p,smb_apasslen);
+ smb_apasswd[smb_apasslen] = 0;
smb_ntpasslen = passlen2;
memcpy(smb_ntpasswd,p+passlen1,smb_ntpasslen);
+ smb_ntpasswd[smb_ntpasslen] = 0;
+
+ /*
+ * Ensure the plaintext passwords are in UNIX format.
+ */
+ if(!doencrypt) {
+ dos_to_unix(smb_apasswd,True);
+ dos_to_unix(smb_ntpasswd,True);
+ }
+
} else {
- /* for Win95 */
- if (passlen1 > passlen2) {
- smb_apasslen = passlen1;
- StrnCpy(smb_apasswd,p,smb_apasslen);
- } else {
- smb_apasslen = passlen2;
- StrnCpy(smb_apasswd,p + passlen1,smb_apasslen);
+ /* we use the first password that they gave */
+ smb_apasslen = passlen1;
+ StrnCpy(smb_apasswd,p,smb_apasslen);
+ /*
+ * Ensure the plaintext password is in UNIX format.
+ */
+ dos_to_unix(smb_apasswd,True);
+
+ /* trim the password */
+ smb_apasslen = strlen(smb_apasswd);
+
+ /* wfwg sometimes uses a space instead of a null */
+ if (strequal(smb_apasswd," ")) {
+ smb_apasslen = 0;
+ *smb_apasswd = 0;
}
}
- if (passlen2 == 1) {
- /* apparently NT sometimes sets passlen2 to 1 when it means 0. This
- tries to work around that problem */
- passlen2 = 0;
- }
+
p += passlen1 + passlen2;
- strcpy(user,p); p = skip_string(p,1);
+ fstrcpy(user,p);
+ p = skip_string(p,1);
+ /*
+ * Incoming user is in DOS codepage format. Convert
+ * to UNIX.
+ */
+ dos_to_unix(user,True);
+ domain = p;
+
DEBUG(3,("Domain=[%s] NativeOS=[%s] NativeLanMan=[%s]\n",
- p,skip_string(p,1),skip_string(p,2)));
+ domain,skip_string(p,1),skip_string(p,2)));
}
DEBUG(3,("sesssetupX:name=[%s]\n",user));
- if (!*user)
- strcpy(user,lp_guestaccount(-1));
+ /* If name ends in $ then I think it's asking about whether a */
+ /* computer with that name (minus the $) has access. For now */
+ /* say yes to everything ending in $. */
- strlower(user);
+ if (*user && (user[strlen(user) - 1] == '$') && (smb_apasslen == 24) && (smb_ntpasslen == 24)) {
+ return session_trust_account(conn, inbuf, outbuf, user,
+ smb_apasswd, smb_apasslen,
+ smb_ntpasswd, smb_ntpasslen);
+ }
- strcpy(sesssetup_user,user);
+ if (done_sesssetup && lp_restrict_anonymous()) {
+ /* tests show that even if browsing is done over already validated connections
+ * without a username and password the domain is still provided, which it
+ * wouldn't be if it was a purely anonymous connection. So, in order to
+ * restrict anonymous, we only deny connections that have no session
+ * information. If a domain has been provided, then it's not a purely
+ * anonymous connection. AAB
+ */
+ if (!*user && !*smb_apasswd && !*domain) {
+ DEBUG(0, ("restrict anonymous is True and anonymous connection attempted. Denying access.\n"));
+ return(ERROR(ERRDOS,ERRnoaccess));
+ }
+ }
+
+ /* If no username is sent use the guest account */
+ if (!*user) {
+ pstrcpy(user,lp_guestaccount(-1));
+ /* If no user and no password then set guest flag. */
+ if( *smb_apasswd == 0)
+ guest = True;
+ }
+
+ pstrcpy(sesssetup_user,user);
reload_services(True);
+ /*
+ * Save the username before mapping. We will use
+ * the original username sent to us for security=server
+ * and security=domain checking.
+ */
+
+ pstrcpy( orig_user, user);
+
+ /* if the username exists as a domain/username pair on the unix system then use
+ that */
+ if (!getpwnam(user)) {
+ pstring user2;
+ slprintf(user2,sizeof(user2),"%s%s%s", domain, lp_winbind_separator(), user);
+ if (getpwnam(user2)) {
+ DEBUG(3,("Using unix username %s\n", user2));
+ pstrcpy(user, user2);
+ }
+ }
+
+ /*
+ * Pass the user through the NT -> unix user mapping
+ * function.
+ */
+
+ (void)map_username(user);
+
+ /*
+ * Do any UNIX username case mangling.
+ */
+ smb_getpwnam(user, True);
+
add_session_user(user);
+ /*
+ * Check if the given username was the guest user with no password.
+ */
+
+ if(!guest && strequal(user,lp_guestaccount(-1)) && (*smb_apasswd == 0))
+ guest = True;
+
+ /*
+ * Check with orig_user for security=server and
+ * security=domain.
+ */
+
+ if (!guest &&
+ !check_server_security(orig_user, domain, user,
+ smb_apasswd, smb_apasslen,
+ smb_ntpasswd, smb_ntpasslen) &&
+ !check_domain_security(orig_user, domain, user,
+ smb_apasswd, smb_apasslen,
+ smb_ntpasswd, smb_ntpasslen) &&
+ !check_hosts_equiv(user)
+ )
+ {
- if (!(lp_security() == SEC_SERVER && server_validate(inbuf)) &&
- !check_hosts_equiv(user))
+ /*
+ * If we get here then the user wasn't guest and the remote
+ * authentication methods failed. Check the authentication
+ * methods on this local server.
+ *
+ * If an NT password was supplied try and validate with that
+ * first. This is superior as the passwords are mixed case
+ * 128 length unicode.
+ */
+
+ if(smb_ntpasslen)
{
+ if(!password_ok(user, smb_ntpasswd,smb_ntpasslen,NULL))
+ DEBUG(2,("NT Password did not match for user '%s' ! Defaulting to Lanman\n", user));
+ else
+ valid_nt_password = True;
+ }
- if (strequal(user,lp_guestaccount(-1)) && (*smb_apasswd == 0))
- guest = True;
-
- /* now check if it's a valid username/password */
- /* If an NT password was supplied try and validate with that
- first. This is superior as the passwords are mixed case 128 length unicode */
- if(smb_ntpasslen && !guest)
- {
- if(!password_ok(user,smb_ntpasswd,smb_ntpasslen,NULL,True))
- DEBUG(0,("NT Password did not match ! Defaulting to Lanman\n"));
- else
- valid_nt_password = True;
- }
- if (!valid_nt_password && !guest && !password_ok(user,smb_apasswd,smb_apasslen,NULL,False))
- {
- if (lp_security() >= SEC_USER) {
-#if (GUEST_SESSSETUP == 0)
- return(ERROR(ERRSRV,ERRbadpw));
-#endif
-#if (GUEST_SESSSETUP == 1)
- if (Get_Pwnam(user,True))
- return(ERROR(ERRSRV,ERRbadpw));
-#endif
- }
- if (*smb_apasswd || !Get_Pwnam(user,True))
- strcpy(user,lp_guestaccount(-1));
- DEBUG(3,("Registered username %s for guest access\n",user));
- guest = True;
- }
+ if (!valid_nt_password && !password_ok(user, smb_apasswd,smb_apasslen,NULL))
+ {
+ if (lp_security() >= SEC_USER)
+ {
+ if (lp_map_to_guest() == NEVER_MAP_TO_GUEST)
+ {
+ DEBUG(1,("Rejecting user '%s': authentication failed\n", user));
+ return bad_password_error(inbuf,outbuf);
+ }
+
+ if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_USER)
+ {
+ if (smb_getpwnam(user,True))
+ {
+ DEBUG(1,("Rejecting user '%s': bad password\n", user));
+ return bad_password_error(inbuf,outbuf);
+ }
+ }
+
+ /*
+ * ..else if lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD
+ * Then always map to guest account - as done below.
+ */
+ }
+
+ if (*smb_apasswd || !smb_getpwnam(user,True))
+ pstrcpy(user,lp_guestaccount(-1));
+ DEBUG(3,("Registered username %s for guest access\n",user));
+ guest = True;
}
+ }
- if (!Get_Pwnam(user,True)) {
- DEBUG(3,("No such user %s - using guest account\n",user));
- strcpy(user,lp_guestaccount(-1));
+ if (!smb_getpwnam(user,True)) {
+ DEBUG(3,("No such user %s [%s] - using guest account\n",user, domain));
+ pstrcpy(user,lp_guestaccount(-1));
guest = True;
}
if (!strequal(user,lp_guestaccount(-1)) &&
lp_servicenumber(user) < 0)
- {
- int homes = lp_servicenumber(HOMES_NAME);
- char *home = get_home_dir(user);
- if (homes >= 0 && home)
- lp_add_home(user,homes,home);
- }
+ {
+ int homes = lp_servicenumber(HOMES_NAME);
+ char *home = get_user_home_dir(user);
+ if (homes >= 0 && home)
+ lp_add_home(user,homes,home);
+ }
/* it's ok - setup a reply */
if (Protocol < PROTOCOL_NT1) {
- outsize = set_message(outbuf,3,0,True);
+ set_message(outbuf,3,0,True);
} else {
char *p;
- outsize = set_message(outbuf,3,3,True);
+ set_message(outbuf,3,3,True);
p = smb_buf(outbuf);
- strcpy(p,"Unix"); p = skip_string(p,1);
- strcpy(p,"Samba "); strcat(p,VERSION); p = skip_string(p,1);
- strcpy(p,my_workgroup()); p = skip_string(p,1);
- outsize = set_message(outbuf,3,PTR_DIFF(p,smb_buf(outbuf)),False);
+ pstrcpy(p,"Unix"); p = skip_string(p,1);
+ pstrcpy(p,"Samba "); pstrcat(p,VERSION); p = skip_string(p,1);
+ pstrcpy(p,global_myworkgroup); p = skip_string(p,1);
+ set_message(outbuf,3,PTR_DIFF(p,smb_buf(outbuf)),False);
/* perhaps grab OS version here?? */
}
@@ -430,64 +973,94 @@ int reply_sesssetup_and_X(char *inbuf,char *outbuf,int length,int bufsize)
user we should become.
*/
{
- struct passwd *pw = Get_Pwnam(user,False);
+ const struct passwd *pw = smb_getpwnam(user,False);
if (!pw) {
DEBUG(1,("Username %s is invalid on this system\n",user));
- return(ERROR(ERRSRV,ERRbadpw));
+ return bad_password_error(inbuf,outbuf);
}
gid = pw->pw_gid;
- SSVAL(outbuf,smb_uid,(uint16)pw->pw_uid);
- SSVAL(inbuf,smb_uid,(uint16)pw->pw_uid);
+ uid = pw->pw_uid;
}
- CVAL(outbuf,smb_vwv0) = smb_com2;
- SSVAL(outbuf,smb_vwv1,(chain_size+outsize)-4);
-
if (guest)
SSVAL(outbuf,smb_vwv2,1);
/* register the name and uid as being validated, so further connections
to a uid can get through without a password, on the same VC */
- register_uid(SVAL(inbuf,smb_uid),gid,user,guest);
+
+ sess_vuid = register_vuid(uid,gid,user,sesssetup_user,domain,guest);
- maxxmit = MIN(maxxmit,smb_bufsize);
+ SSVAL(outbuf,smb_uid,sess_vuid);
+ SSVAL(inbuf,smb_uid,sess_vuid);
- if (smb_com2 != 0xFF)
- outsize += chain_reply(smb_com2,inbuf,inbuf+smb_off2+4,
- outbuf,outbuf+outsize,
- length,bufsize);
+ if (!done_sesssetup)
+ max_send = MIN(max_send,smb_bufsize);
- return(outsize);
+ DEBUG(6,("Client requested max send size of %d\n", max_send));
+
+ done_sesssetup = True;
+
+ return chain_reply(inbuf,outbuf,length,bufsize);
}
/****************************************************************************
reply to a chkpth
****************************************************************************/
-int reply_chkpth(char *inbuf,char *outbuf)
+int reply_chkpth(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
{
int outsize = 0;
- int cnum,mode;
+ int mode;
pstring name;
BOOL ok = False;
-
- cnum = SVAL(inbuf,smb_tid);
-
- strcpy(name,smb_buf(inbuf) + 1);
- unix_convert(name,cnum);
+ BOOL bad_path = False;
+ SMB_STRUCT_STAT st;
+
+ pstrcpy(name,smb_buf(inbuf) + 1);
+
+ RESOLVE_DFSPATH(name, conn, inbuf, outbuf);
+
+ unix_convert(name,conn,0,&bad_path,&st);
mode = SVAL(inbuf,smb_vwv0);
- if (check_name(name,cnum))
- ok = directory_exist(name,NULL);
+ if (check_name(name,conn)) {
+ if(VALID_STAT(st))
+ ok = S_ISDIR(st.st_mode);
+ else
+ ok = vfs_directory_exist(conn,name,NULL);
+ }
if (!ok)
- return(ERROR(ERRDOS,ERRbadpath));
-
+ {
+ /* We special case this - as when a Windows machine
+ is parsing a path is steps through the components
+ one at a time - if a component fails it expects
+ ERRbadpath, not ERRbadfile.
+ */
+ if(errno == ENOENT)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
+
+#if 0
+ /* Ugly - NT specific hack - maybe not needed ? (JRA) */
+ if((errno == ENOTDIR) && (Protocol >= PROTOCOL_NT1) &&
+ (get_remote_arch() == RA_WINNT))
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbaddirectory;
+ }
+#endif
+
+ return(UNIXERROR(ERRDOS,ERRbadpath));
+ }
+
outsize = set_message(outbuf,0,0,True);
-
- DEBUG(3,("%s chkpth %s cnum=%d mode=%d\n",timestring(),name,cnum,mode));
-
+
+ DEBUG(3,("chkpth %s mode=%d\n", name, mode));
+
return(outsize);
}
@@ -495,66 +1068,81 @@ int reply_chkpth(char *inbuf,char *outbuf)
/****************************************************************************
reply to a getatr
****************************************************************************/
-int reply_getatr(char *inbuf,char *outbuf)
+int reply_getatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
{
pstring fname;
- int cnum;
int outsize = 0;
- struct stat sbuf;
+ SMB_STRUCT_STAT sbuf;
BOOL ok = False;
int mode=0;
- uint32 size=0;
+ SMB_OFF_T size=0;
time_t mtime=0;
-
- cnum = SVAL(inbuf,smb_tid);
-
- strcpy(fname,smb_buf(inbuf) + 1);
- unix_convert(fname,cnum);
+ BOOL bad_path = False;
+
+ pstrcpy(fname,smb_buf(inbuf) + 1);
+ RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
+
+ /* if((SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES) && dfs_redirect(fname,conn)) return(dfs_path_error(inbuf,outbuf));
+ */
/* dos smetimes asks for a stat of "" - it returns a "hidden directory"
under WfWg - weird! */
if (! (*fname))
- {
- mode = aHIDDEN | aDIR;
- if (!CAN_WRITE(cnum)) mode |= aRONLY;
- size = 0;
- mtime = 0;
- ok = True;
- }
+ {
+ mode = aHIDDEN | aDIR;
+ if (!CAN_WRITE(conn)) mode |= aRONLY;
+ size = 0;
+ mtime = 0;
+ ok = True;
+ }
else
- if (check_name(fname,cnum))
+ {
+ unix_convert(fname,conn,0,&bad_path,&sbuf);
+ if (check_name(fname,conn))
+ {
+ if (VALID_STAT(sbuf) || dos_stat(fname,&sbuf) == 0)
{
- if (sys_stat(fname,&sbuf) == 0)
- {
- mode = dos_mode(cnum,fname,&sbuf);
- size = sbuf.st_size;
- mtime = sbuf.st_mtime;
- if (mode & aDIR)
- size = 0;
- ok = True;
- }
- else
- DEBUG(3,("stat of %s failed (%s)\n",fname,strerror(errno)));
+ mode = dos_mode(conn,fname,&sbuf);
+ size = sbuf.st_size;
+ mtime = sbuf.st_mtime;
+ if (mode & aDIR)
+ size = 0;
+ ok = True;
+ }
+ else
+ DEBUG(3,("stat of %s failed (%s)\n",fname,strerror(errno)));
}
+ }
if (!ok)
+ {
+ if((errno == ENOENT) && bad_path)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
+
return(UNIXERROR(ERRDOS,ERRbadfile));
-
+ }
+
outsize = set_message(outbuf,10,0,True);
SSVAL(outbuf,smb_vwv0,mode);
- put_dos_date3(outbuf,smb_vwv1,mtime);
- SIVAL(outbuf,smb_vwv3,size);
+ if(lp_dos_filetime_resolution(SNUM(conn)) )
+ put_dos_date3(outbuf,smb_vwv1,mtime & ~1);
+ else
+ put_dos_date3(outbuf,smb_vwv1,mtime);
+ SIVAL(outbuf,smb_vwv3,(uint32)size);
if (Protocol >= PROTOCOL_NT1) {
char *p = strrchr(fname,'/');
uint16 flg2 = SVAL(outbuf,smb_flg2);
if (!p) p = fname;
- if (!is_8_3(fname))
+ if (!is_8_3(fname, True))
SSVAL(outbuf,smb_flg2,flg2 | 0x40); /* IS_LONG_NAME */
}
- DEBUG(3,("%s getatr name=%s mode=%d size=%d\n",timestring(),fname,mode,size));
+ DEBUG( 3, ( "getatr name=%s mode=%d size=%d\n", fname, mode, (uint32)size ) );
return(outsize);
}
@@ -563,36 +1151,43 @@ int reply_getatr(char *inbuf,char *outbuf)
/****************************************************************************
reply to a setatr
****************************************************************************/
-int reply_setatr(char *inbuf,char *outbuf)
+int reply_setatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
{
pstring fname;
- int cnum;
int outsize = 0;
BOOL ok=False;
int mode;
time_t mtime;
-
- cnum = SVAL(inbuf,smb_tid);
-
- strcpy(fname,smb_buf(inbuf) + 1);
- unix_convert(fname,cnum);
+ SMB_STRUCT_STAT st;
+ BOOL bad_path = False;
+
+ pstrcpy(fname,smb_buf(inbuf) + 1);
+ unix_convert(fname,conn,0,&bad_path,&st);
mode = SVAL(inbuf,smb_vwv0);
mtime = make_unix_date3(inbuf+smb_vwv1);
- if (directory_exist(fname,NULL))
+ if (VALID_STAT_OF_DIR(st) || vfs_directory_exist(conn, fname, NULL))
mode |= aDIR;
- if (check_name(fname,cnum))
- ok = (dos_chmod(cnum,fname,mode,NULL) == 0);
+ if (check_name(fname,conn))
+ ok = (file_chmod(conn,fname,mode,NULL) == 0);
if (ok)
- ok = set_filetime(fname,mtime);
+ ok = set_filetime(conn,fname,mtime);
if (!ok)
+ {
+ if((errno == ENOENT) && bad_path)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
+
return(UNIXERROR(ERRDOS,ERRnoaccess));
-
+ }
+
outsize = set_message(outbuf,0,0,True);
- DEBUG(3,("%s setatr name=%s mode=%d\n",timestring(),fname,mode));
+ DEBUG( 3, ( "setatr name=%s mode=%d\n", fname, mode ) );
return(outsize);
}
@@ -601,15 +1196,12 @@ int reply_setatr(char *inbuf,char *outbuf)
/****************************************************************************
reply to a dskattr
****************************************************************************/
-int reply_dskattr(char *inbuf,char *outbuf)
+int reply_dskattr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
{
- int cnum;
int outsize = 0;
- int dfree,dsize,bsize;
+ SMB_BIG_UINT dfree,dsize,bsize;
- cnum = SVAL(inbuf,smb_tid);
-
- sys_disk_free(".",&bsize,&dfree,&dsize);
+ conn->vfs_ops.disk_free(".",True,&bsize,&dfree,&dsize);
outsize = set_message(outbuf,5,0,True);
@@ -617,9 +1209,9 @@ int reply_dskattr(char *inbuf,char *outbuf)
SSVAL(outbuf,smb_vwv1,bsize/512);
SSVAL(outbuf,smb_vwv2,512);
SSVAL(outbuf,smb_vwv3,dfree);
-
- DEBUG(3,("%s dskattr cnum=%d dfree=%d\n",timestring(),cnum,dfree));
-
+
+ DEBUG(3,("dskattr dfree=%d\n", (unsigned int)dfree));
+
return(outsize);
}
@@ -628,15 +1220,15 @@ int reply_dskattr(char *inbuf,char *outbuf)
reply to a search
Can be called from SMBsearch, SMBffirst or SMBfunique.
****************************************************************************/
-int reply_search(char *inbuf,char *outbuf)
+int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
{
pstring mask;
pstring directory;
pstring fname;
- int size,mode;
+ SMB_OFF_T size;
+ int mode;
time_t date;
int dirtype;
- int cnum;
int outsize = 0;
int numentries = 0;
BOOL finished = False;
@@ -651,6 +1243,7 @@ int reply_search(char *inbuf,char *outbuf)
BOOL check_descend = False;
BOOL expect_close = False;
BOOL can_open = True;
+ BOOL bad_path = False;
*mask = *directory = *fname = 0;
@@ -658,8 +1251,6 @@ int reply_search(char *inbuf,char *outbuf)
if(CVAL(inbuf,smb_com) == SMBffirst)
expect_close = True;
- cnum = SVAL(inbuf,smb_tid);
-
outsize = set_message(outbuf,1,3,True);
maxentries = SVAL(inbuf,smb_vwv0);
dirtype = SVAL(inbuf,smb_vwv1);
@@ -669,164 +1260,141 @@ int reply_search(char *inbuf,char *outbuf)
/* dirtype &= ~aDIR; */
- DEBUG(5,("path=%s status_len=%d\n",path,status_len));
-
-
if (status_len == 0)
- {
- pstring dir2;
+ {
+ pstring dir2;
- strcpy(directory,smb_buf(inbuf)+1);
- strcpy(dir2,smb_buf(inbuf)+1);
- unix_convert(directory,cnum);
- unix_format(dir2);
+ pstrcpy(directory,smb_buf(inbuf)+1);
+ pstrcpy(dir2,smb_buf(inbuf)+1);
+ unix_convert(directory,conn,0,&bad_path,NULL);
+ unix_format(dir2);
- if (!check_name(directory,cnum))
- can_open = False;
+ if (!check_name(directory,conn))
+ can_open = False;
- p = strrchr(dir2,'/');
- if (p == NULL)
- {strcpy(mask,dir2);*dir2 = 0;}
- else
- {*p = 0;strcpy(mask,p+1);}
+ p = strrchr(dir2,'/');
+ if (p == NULL)
+ {
+ pstrcpy(mask,dir2);
+ *dir2 = 0;
+ }
+ else
+ {
+ *p = 0;
+ pstrcpy(mask,p+1);
+ }
- p = strrchr(directory,'/');
- if (!p)
- *directory = 0;
- else
- *p = 0;
+ p = strrchr(directory,'/');
+ if (!p)
+ *directory = 0;
+ else
+ *p = 0;
- if (strlen(directory) == 0)
- strcpy(directory,"./");
- bzero(status,21);
- CVAL(status,0) = dirtype;
- }
+ if (strlen(directory) == 0)
+ pstrcpy(directory,"./");
+ memset((char *)status,'\0',21);
+ CVAL(status,0) = dirtype;
+ }
else
- {
- memcpy(status,smb_buf(inbuf) + 1 + strlen(path) + 4,21);
- memcpy(mask,status+1,11);
- mask[11] = 0;
- dirtype = CVAL(status,0) & 0x1F;
- Connections[cnum].dirptr = dptr_fetch(status+12,&dptr_num);
- if (!Connections[cnum].dirptr)
- goto SearchEmpty;
- string_set(&Connections[cnum].dirpath,dptr_path(dptr_num));
- if (!case_sensitive)
- strnorm(mask);
- }
-
- /* turn strings of spaces into a . */
{
- trim_string(mask,NULL," ");
- if ((p = strrchr(mask,' ')))
- {
- fstring ext;
- strcpy(ext,p+1);
- *p = 0;
- trim_string(mask,NULL," ");
- strcat(mask,".");
- strcat(mask,ext);
- }
+ memcpy(status,smb_buf(inbuf) + 1 + strlen(path) + 4,21);
+ dirtype = CVAL(status,0) & 0x1F;
+ conn->dirptr = dptr_fetch(status+12,&dptr_num);
+ if (!conn->dirptr)
+ goto SearchEmpty;
+ string_set(&conn->dirpath,dptr_path(dptr_num));
+ fstrcpy(mask, dptr_wcard(dptr_num));
}
+ if (can_open)
{
- for (p=mask; *p; p++)
+ p = smb_buf(outbuf) + 3;
+
+ ok = True;
+
+ if (status_len == 0)
+ {
+ dptr_num = dptr_create(conn,directory,True,expect_close,SVAL(inbuf,smb_pid));
+ if (dptr_num < 0)
{
- if (*p != '?' && *p != '*' && !isdoschar(*p))
- {
- DEBUG(5,("Invalid char [%c] in search mask?\n",*p));
- *p = '?';
- }
+ if(dptr_num == -2)
+ {
+ if((errno == ENOENT) && bad_path)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
+ return (UNIXERROR(ERRDOS,ERRnofids));
+ }
+ return(ERROR(ERRDOS,ERRnofids));
}
- }
-
- if (!strchr(mask,'.') && strlen(mask)>8)
- {
- fstring tmp;
- strcpy(tmp,&mask[8]);
- mask[8] = '.';
- mask[9] = 0;
- strcat(mask,tmp);
+ dptr_set_wcard(dptr_num, strdup(mask));
}
- DEBUG(5,("mask=%s directory=%s\n",mask,directory));
-
- if (can_open)
- {
- p = smb_buf(outbuf) + 3;
-
- ok = True;
-
- if (status_len == 0)
- {
- dptr_num = dptr_create(cnum,directory,expect_close,SVAL(inbuf,smb_pid));
- if (dptr_num < 0)
- return(ERROR(ERRDOS,ERRnofids));
- }
-
- DEBUG(4,("dptr_num is %d\n",dptr_num));
+ DEBUG(4,("dptr_num is %d\n",dptr_num));
- if (ok)
- {
- if ((dirtype&0x1F) == aVOLID)
- {
- memcpy(p,status,21);
- make_dir_struct(p,"???????????",volume_label(SNUM(cnum)),0,aVOLID,0);
- dptr_fill(p+12,dptr_num);
- if (dptr_zero(p+12) && (status_len==0))
- numentries = 1;
- else
- numentries = 0;
- p += DIR_STRUCT_SIZE;
- }
- else
- {
- DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",Connections[cnum].dirpath,lp_dontdescend(SNUM(cnum))));
- if (in_list(Connections[cnum].dirpath,
- lp_dontdescend(SNUM(cnum)),True))
- check_descend = True;
-
- for (i=numentries;(i<maxentries) && !finished;i++)
- {
- finished =
- !get_dir_entry(cnum,mask,dirtype,fname,&size,&mode,&date,check_descend);
- if (!finished)
- {
- memcpy(p,status,21);
- make_dir_struct(p,mask,fname,size,mode,date);
- dptr_fill(p+12,dptr_num);
- numentries++;
- }
- p += DIR_STRUCT_SIZE;
- }
- }
- }
- }
+ if (ok)
+ {
+ if ((dirtype&0x1F) == aVOLID)
+ {
+ memcpy(p,status,21);
+ make_dir_struct(p,"???????????",volume_label(SNUM(conn)),0,aVOLID,0);
+ dptr_fill(p+12,dptr_num);
+ if (dptr_zero(p+12) && (status_len==0))
+ numentries = 1;
+ else
+ numentries = 0;
+ p += DIR_STRUCT_SIZE;
+ }
+ else
+ {
+ DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",
+ conn->dirpath,lp_dontdescend(SNUM(conn))));
+ if (in_list(conn->dirpath, lp_dontdescend(SNUM(conn)),True))
+ check_descend = True;
+
+ for (i=numentries;(i<maxentries) && !finished;i++)
+ {
+ finished =
+ !get_dir_entry(conn,mask,dirtype,fname,&size,&mode,&date,check_descend);
+ if (!finished)
+ {
+ memcpy(p,status,21);
+ make_dir_struct(p,mask,fname,size,mode,date);
+ dptr_fill(p+12,dptr_num);
+ numentries++;
+ }
+ p += DIR_STRUCT_SIZE;
+ }
+ }
+ } /* if (ok ) */
+ }
- SearchEmpty:
+ SearchEmpty:
if (numentries == 0 || !ok)
- {
- CVAL(outbuf,smb_rcls) = ERRDOS;
- SSVAL(outbuf,smb_err,ERRnofiles);
- }
+ {
+ CVAL(outbuf,smb_rcls) = ERRDOS;
+ SSVAL(outbuf,smb_err,ERRnofiles);
+ dptr_close(&dptr_num);
+ }
/* If we were called as SMBffirst with smb_search_id == NULL
and no entries were found then return error and close dirptr
(X/Open spec) */
if(ok && expect_close && numentries == 0 && status_len == 0)
- {
- CVAL(outbuf,smb_rcls) = ERRDOS;
- SSVAL(outbuf,smb_err,ERRnofiles);
- /* Also close the dptr - we know it's gone */
- dptr_close(dptr_num);
- }
+ {
+ CVAL(outbuf,smb_rcls) = ERRDOS;
+ SSVAL(outbuf,smb_err,ERRnofiles);
+ /* Also close the dptr - we know it's gone */
+ dptr_close(&dptr_num);
+ }
/* If we were called as SMBfunique, then we can close the dirptr now ! */
if(dptr_num >= 0 && CVAL(inbuf,smb_com) == SMBfunique)
- dptr_close(dptr_num);
+ dptr_close(&dptr_num);
SSVAL(outbuf,smb_vwv0,numentries);
SSVAL(outbuf,smb_vwv1,3 + numentries * DIR_STRUCT_SIZE);
@@ -842,12 +1410,11 @@ int reply_search(char *inbuf,char *outbuf)
smb_setlen(outbuf,outsize - 4);
if ((! *directory) && dptr_path(dptr_num))
- sprintf(directory,"(%s)",dptr_path(dptr_num));
+ slprintf(directory, sizeof(directory)-1, "(%s)",dptr_path(dptr_num));
- DEBUG(4,("%s %s mask=%s path=%s cnum=%d dtype=%d nument=%d of %d\n",
- timestring(),
- smb_fn_name(CVAL(inbuf,smb_com)),
- mask,directory,cnum,dirtype,numentries,maxentries));
+ DEBUG( 4, ( "%s mask=%s path=%s dtype=%d nument=%d of %d\n",
+ smb_fn_name(CVAL(inbuf,smb_com)),
+ mask, directory, dirtype, numentries, maxentries ) );
return(outsize);
}
@@ -856,16 +1423,13 @@ int reply_search(char *inbuf,char *outbuf)
/****************************************************************************
reply to a fclose (stop directory search)
****************************************************************************/
-int reply_fclose(char *inbuf,char *outbuf)
+int reply_fclose(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
{
- int cnum;
int outsize = 0;
int status_len;
char *path;
char status[21];
- int dptr_num= -1;
-
- cnum = SVAL(inbuf,smb_tid);
+ int dptr_num= -2;
outsize = set_message(outbuf,1,0,True);
path = smb_buf(inbuf) + 1;
@@ -879,12 +1443,12 @@ int reply_fclose(char *inbuf,char *outbuf)
if(dptr_fetch(status+12,&dptr_num)) {
/* Close the dptr - we know it's gone */
- dptr_close(dptr_num);
+ dptr_close(&dptr_num);
}
SSVAL(outbuf,smb_vwv0,0);
- DEBUG(3,("%s search close cnum=%d\n",timestring(),cnum));
+ DEBUG(3,("search close\n"));
return(outsize);
}
@@ -893,63 +1457,76 @@ int reply_fclose(char *inbuf,char *outbuf)
/****************************************************************************
reply to an open
****************************************************************************/
-int reply_open(char *inbuf,char *outbuf)
+
+int reply_open(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
{
pstring fname;
- int cnum;
- int fnum = -1;
int outsize = 0;
int fmode=0;
int share_mode;
- int size = 0;
+ SMB_OFF_T size = 0;
time_t mtime=0;
- int unixmode;
+ mode_t unixmode;
int rmode=0;
- struct stat sbuf;
-
- cnum = SVAL(inbuf,smb_tid);
-
+ SMB_STRUCT_STAT sbuf;
+ BOOL bad_path = False;
+ files_struct *fsp;
+ int oplock_request = CORE_OPLOCK_REQUEST(inbuf);
+
share_mode = SVAL(inbuf,smb_vwv0);
- strcpy(fname,smb_buf(inbuf)+1);
- unix_convert(fname,cnum);
-
- fnum = find_free_file();
- if (fnum < 0)
- return(ERROR(ERRSRV,ERRnofids));
+ pstrcpy(fname,smb_buf(inbuf)+1);
- if (!check_name(fname,cnum))
- return(UNIXERROR(ERRDOS,ERRnoaccess));
-
- unixmode = unix_mode(cnum,aARCH);
+ RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
+
+ unix_convert(fname,conn,0,&bad_path,NULL);
+
+ unixmode = unix_mode(conn,aARCH,fname);
- open_file_shared(fnum,cnum,fname,share_mode,3,unixmode,&rmode,NULL);
+ fsp = open_file_shared(conn,fname,share_mode,(FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),
+ unixmode, oplock_request,&rmode,NULL);
- if (!Files[fnum].open)
+ if (!fsp)
+ {
+ if((errno == ENOENT) && bad_path)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
- if (fstat(Files[fnum].fd,&sbuf) != 0) {
- close_file(fnum);
+ if (fsp->conn->vfs_ops.fstat(fsp->fd,&sbuf) != 0) {
+ close_file(fsp,False);
return(ERROR(ERRDOS,ERRnoaccess));
}
size = sbuf.st_size;
- fmode = dos_mode(cnum,fname,&sbuf);
+ fmode = dos_mode(conn,fname,&sbuf);
mtime = sbuf.st_mtime;
if (fmode & aDIR) {
DEBUG(3,("attempt to open a directory %s\n",fname));
- close_file(fnum);
+ close_file(fsp,False);
return(ERROR(ERRDOS,ERRnoaccess));
}
outsize = set_message(outbuf,7,0,True);
- SSVAL(outbuf,smb_vwv0,fnum);
+ SSVAL(outbuf,smb_vwv0,fsp->fnum);
SSVAL(outbuf,smb_vwv1,fmode);
- put_dos_date3(outbuf,smb_vwv2,mtime);
- SIVAL(outbuf,smb_vwv4,size);
+ if(lp_dos_filetime_resolution(SNUM(conn)) )
+ put_dos_date3(outbuf,smb_vwv2,mtime & ~1);
+ else
+ put_dos_date3(outbuf,smb_vwv2,mtime);
+ SIVAL(outbuf,smb_vwv4,(uint32)size);
SSVAL(outbuf,smb_vwv6,rmode);
+
+ if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
+ CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
+ }
+ if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type))
+ CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
return(outsize);
}
@@ -957,165 +1534,213 @@ int reply_open(char *inbuf,char *outbuf)
/****************************************************************************
reply to an open and X
****************************************************************************/
-int reply_open_and_X(char *inbuf,char *outbuf,int length,int bufsize)
+int reply_open_and_X(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
{
pstring fname;
- int cnum = SVAL(inbuf,smb_tid);
- int fnum = -1;
- int outsize = 0;
- int openmode = 0;
- int smb_com2 = CVAL(inbuf,smb_vwv0);
- int smb_off2 = SVAL(inbuf,smb_vwv1);
int smb_mode = SVAL(inbuf,smb_vwv3);
int smb_attr = SVAL(inbuf,smb_vwv5);
+ /* Breakout the oplock request bits so we can set the
+ reply bits separately. */
+ BOOL ex_oplock_request = EXTENDED_OPLOCK_REQUEST(inbuf);
+ BOOL core_oplock_request = CORE_OPLOCK_REQUEST(inbuf);
+ BOOL oplock_request = ex_oplock_request | core_oplock_request;
#if 0
int open_flags = SVAL(inbuf,smb_vwv2);
int smb_sattr = SVAL(inbuf,smb_vwv4);
uint32 smb_time = make_unix_date3(inbuf+smb_vwv6);
#endif
int smb_ofun = SVAL(inbuf,smb_vwv8);
- int unixmode;
- int size=0,fmode=0,mtime=0,rmode=0;
- struct stat sbuf;
+ mode_t unixmode;
+ SMB_OFF_T size=0;
+ int fmode=0,mtime=0,rmode=0;
+ SMB_STRUCT_STAT sbuf;
int smb_action = 0;
+ BOOL bad_path = False;
+ files_struct *fsp;
+
+ /* If it's an IPC, pass off the pipe handler. */
+ if (IS_IPC(conn)) {
+ if (lp_nt_pipe_support())
+ return reply_open_pipe_and_X(conn, inbuf,outbuf,length,bufsize);
+ else
+ return (ERROR(ERRSRV,ERRaccess));
+ }
/* XXXX we need to handle passed times, sattr and flags */
- strcpy(fname,smb_buf(inbuf));
- unix_convert(fname,cnum);
-
- /* now add create and trunc bits */
- if (smb_ofun & 0x10)
- openmode |= O_CREAT;
- if ((smb_ofun & 0x3) == 2)
- openmode |= O_TRUNC;
-
- fnum = find_free_file();
- if (fnum < 0)
- return(ERROR(ERRSRV,ERRnofids));
+ pstrcpy(fname,smb_buf(inbuf));
- if (!check_name(fname,cnum))
- return(UNIXERROR(ERRDOS,ERRnoaccess));
+ RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
- unixmode = unix_mode(cnum,smb_attr | aARCH);
+ unix_convert(fname,conn,0,&bad_path,NULL);
+
+ unixmode = unix_mode(conn,smb_attr | aARCH, fname);
- open_file_shared(fnum,cnum,fname,smb_mode,smb_ofun,unixmode,
- &rmode,&smb_action);
+ fsp = open_file_shared(conn,fname,smb_mode,smb_ofun,unixmode,
+ oplock_request, &rmode,&smb_action);
- if (!Files[fnum].open)
+ if (!fsp)
+ {
+ if((errno == ENOENT) && bad_path)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
- if (fstat(Files[fnum].fd,&sbuf) != 0) {
- close_file(fnum);
+ if (fsp->conn->vfs_ops.fstat(fsp->fd,&sbuf) != 0) {
+ close_file(fsp,False);
return(ERROR(ERRDOS,ERRnoaccess));
}
size = sbuf.st_size;
- fmode = dos_mode(cnum,fname,&sbuf);
+ fmode = dos_mode(conn,fname,&sbuf);
mtime = sbuf.st_mtime;
if (fmode & aDIR) {
- close_file(fnum);
+ close_file(fsp,False);
return(ERROR(ERRDOS,ERRnoaccess));
}
- outsize = set_message(outbuf,15,0,True);
- CVAL(outbuf,smb_vwv0) = smb_com2;
- SSVAL(outbuf,smb_vwv1,(chain_size+outsize)-4);
- SSVAL(outbuf,smb_vwv2,fnum);
+ /* If the caller set the extended oplock request bit
+ and we granted one (by whatever means) - set the
+ correct bit for extended oplock reply.
+ */
+
+ if (ex_oplock_request && lp_fake_oplocks(SNUM(conn))) {
+ smb_action |= EXTENDED_OPLOCK_GRANTED;
+ }
+
+ if(ex_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
+ smb_action |= EXTENDED_OPLOCK_GRANTED;
+ }
+
+ /* If the caller set the core oplock request bit
+ and we granted one (by whatever means) - set the
+ correct bit for core oplock reply.
+ */
+
+ if (core_oplock_request && lp_fake_oplocks(SNUM(conn))) {
+ CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
+ }
+
+ if(core_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
+ CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
+ }
+
+ set_message(outbuf,15,0,True);
+ SSVAL(outbuf,smb_vwv2,fsp->fnum);
SSVAL(outbuf,smb_vwv3,fmode);
- put_dos_date3(outbuf,smb_vwv4,mtime);
- SIVAL(outbuf,smb_vwv6,size);
+ if(lp_dos_filetime_resolution(SNUM(conn)) )
+ put_dos_date3(outbuf,smb_vwv4,mtime & ~1);
+ else
+ put_dos_date3(outbuf,smb_vwv4,mtime);
+ SIVAL(outbuf,smb_vwv6,(uint32)size);
SSVAL(outbuf,smb_vwv8,rmode);
SSVAL(outbuf,smb_vwv11,smb_action);
- chain_fnum = fnum;
-
- if (smb_com2 != 0xFF)
- outsize += chain_reply(smb_com2,inbuf,inbuf+smb_off2+4,
- outbuf,outbuf+outsize,
- length,bufsize);
-
- chain_fnum = -1;
-
- return(outsize);
+ return chain_reply(inbuf,outbuf,length,bufsize);
}
/****************************************************************************
reply to a SMBulogoffX
****************************************************************************/
-int reply_ulogoffX(char *inbuf,char *outbuf,int length,int bufsize)
+int reply_ulogoffX(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
{
- int outsize = 0;
- int smb_com2 = CVAL(inbuf,smb_vwv0);
- int smb_off2 = SVAL(inbuf,smb_vwv1);
- int uid = SVAL(inbuf,smb_uid);
+ uint16 vuid = SVAL(inbuf,smb_uid);
+ user_struct *vuser = get_valid_user_struct(vuid);
- invalidate_uid(uid);
+ if(vuser == 0) {
+ DEBUG(3,("ulogoff, vuser id %d does not map to user.\n", vuid));
+ }
- outsize = set_message(outbuf,2,0,True);
- CVAL(outbuf,smb_vwv0) = smb_com2;
- SSVAL(outbuf,smb_vwv1,(chain_size+outsize)-4);
+ /* in user level security we are supposed to close any files
+ open by this user */
+ if ((vuser != 0) && (lp_security() != SEC_SHARE)) {
+ file_close_user(vuid);
+ }
- DEBUG(3,("%s ulogoffX uid=%d\n",timestring(),uid));
+ invalidate_vuid(vuid);
- if (smb_com2 != 0xFF)
- outsize += chain_reply(smb_com2,inbuf,inbuf+smb_off2+4,
- outbuf,outbuf+outsize,
- length,bufsize);
+ set_message(outbuf,2,0,True);
-
- return(outsize);
+ DEBUG( 3, ( "ulogoffX vuid=%d\n", vuid ) );
+
+ return chain_reply(inbuf,outbuf,length,bufsize);
}
/****************************************************************************
- reply to a mknew
+ reply to a mknew or a create
****************************************************************************/
-int reply_mknew(char *inbuf,char *outbuf)
+int reply_mknew(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
{
pstring fname;
- int cnum,com;
- int fnum = -1;
+ int com;
int outsize = 0;
int createmode;
mode_t unixmode;
-
+ int ofun = 0;
+ BOOL bad_path = False;
+ files_struct *fsp;
+ int oplock_request = CORE_OPLOCK_REQUEST(inbuf);
+
com = SVAL(inbuf,smb_com);
- cnum = SVAL(inbuf,smb_tid);
createmode = SVAL(inbuf,smb_vwv0);
- strcpy(fname,smb_buf(inbuf)+1);
- unix_convert(fname,cnum);
+ pstrcpy(fname,smb_buf(inbuf)+1);
+
+ RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
+
+ unix_convert(fname,conn,0,&bad_path,NULL);
if (createmode & aVOLID)
{
DEBUG(0,("Attempt to create file (%s) with volid set - please report this\n",fname));
}
- unixmode = unix_mode(cnum,createmode);
+ unixmode = unix_mode(conn,createmode,fname);
- if (com == SMBmknew && file_exist(fname,NULL))
- return(ERROR(ERRDOS,ERRfilexists));
-
- fnum = find_free_file();
- if (fnum < 0)
- return(ERROR(ERRSRV,ERRnofids));
-
- if (!check_name(fname,cnum))
- return(UNIXERROR(ERRDOS,ERRnoaccess));
+ if(com == SMBmknew)
+ {
+ /* We should fail if file exists. */
+ ofun = FILE_CREATE_IF_NOT_EXIST;
+ }
+ else
+ {
+ /* SMBcreate - Create if file doesn't exist, truncate if it does. */
+ ofun = FILE_CREATE_IF_NOT_EXIST|FILE_EXISTS_TRUNCATE;
+ }
- open_file(fnum,cnum,fname,O_RDWR | O_CREAT | O_TRUNC,unixmode);
+ /* Open file in dos compatibility share mode. */
+ fsp = open_file_shared(conn,fname,SET_DENY_MODE(DENY_FCB)|SET_OPEN_MODE(DOS_OPEN_FCB),
+ ofun, unixmode, oplock_request, NULL, NULL);
- if (!Files[fnum].open)
+ if (!fsp)
+ {
+ if((errno == ENOENT) && bad_path)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
return(UNIXERROR(ERRDOS,ERRnoaccess));
-
+ }
+
outsize = set_message(outbuf,1,0,True);
- SSVAL(outbuf,smb_vwv0,fnum);
-
- DEBUG(2,("new file %s\n",fname));
- DEBUG(3,("%s mknew %s fd=%d fnum=%d cnum=%d dmode=%d umode=%o\n",timestring(),fname,Files[fnum].fd,fnum,cnum,createmode,unixmode));
-
+ SSVAL(outbuf,smb_vwv0,fsp->fnum);
+
+ if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
+ CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
+ }
+
+ if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type))
+ CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
+
+ DEBUG( 2, ( "new file %s\n", fname ) );
+ DEBUG( 3, ( "mknew %s fd=%d dmode=%d umode=%o\n",
+ fname, fsp->fd, createmode, (int)unixmode ) );
+
return(outsize);
}
@@ -1123,45 +1748,60 @@ int reply_mknew(char *inbuf,char *outbuf)
/****************************************************************************
reply to a create temporary file
****************************************************************************/
-int reply_ctemp(char *inbuf,char *outbuf)
+int reply_ctemp(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
{
pstring fname;
pstring fname2;
- int cnum;
- int fnum = -1;
int outsize = 0;
int createmode;
mode_t unixmode;
-
- cnum = SVAL(inbuf,smb_tid);
+ BOOL bad_path = False;
+ files_struct *fsp;
+ int oplock_request = CORE_OPLOCK_REQUEST(inbuf);
+
createmode = SVAL(inbuf,smb_vwv0);
- sprintf(fname,"%s/TMXXXXXX",smb_buf(inbuf)+1);
- unix_convert(fname,cnum);
-
- unixmode = unix_mode(cnum,createmode);
-
- fnum = find_free_file();
- if (fnum < 0)
- return(ERROR(ERRSRV,ERRnofids));
+ pstrcpy(fname,smb_buf(inbuf)+1);
+ pstrcat(fname,"/TMXXXXXX");
- if (!check_name(fname,cnum))
- return(UNIXERROR(ERRDOS,ERRnoaccess));
+ RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
- strcpy(fname2,(char *)mktemp(fname));
+ unix_convert(fname,conn,0,&bad_path,NULL);
+
+ unixmode = unix_mode(conn,createmode,fname);
+
+ pstrcpy(fname2,(char *)smbd_mktemp(fname));
- open_file(fnum,cnum,fname2,O_RDWR | O_CREAT | O_TRUNC,unixmode);
+ /* Open file in dos compatibility share mode. */
+ /* We should fail if file exists. */
+ fsp = open_file_shared(conn,fname2,SET_DENY_MODE(DENY_FCB)|SET_OPEN_MODE(DOS_OPEN_FCB),
+ (FILE_CREATE_IF_NOT_EXIST|FILE_EXISTS_FAIL), unixmode, oplock_request, NULL, NULL);
- if (!Files[fnum].open)
+ if (!fsp)
+ {
+ if((errno == ENOENT) && bad_path)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
outsize = set_message(outbuf,1,2 + strlen(fname2),True);
- SSVAL(outbuf,smb_vwv0,fnum);
+ SSVAL(outbuf,smb_vwv0,fsp->fnum);
CVAL(smb_buf(outbuf),0) = 4;
- strcpy(smb_buf(outbuf) + 1,fname2);
-
- DEBUG(2,("created temp file %s\n",fname2));
- DEBUG(3,("%s ctemp %s fd=%d fnum=%d cnum=%d dmode=%d umode=%o\n",timestring(),fname2,Files[fnum].fd,fnum,cnum,createmode,unixmode));
+ pstrcpy(smb_buf(outbuf) + 1,fname2);
+
+ if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
+ CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
+ }
+ if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type))
+ CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
+
+ DEBUG( 2, ( "created temp file %s\n", fname2 ) );
+ DEBUG( 3, ( "ctemp %s fd=%d dmode=%d umode=%o\n",
+ fname2, fsp->fd, createmode, (int)unixmode ) );
+
return(outsize);
}
@@ -1169,31 +1809,33 @@ int reply_ctemp(char *inbuf,char *outbuf)
/*******************************************************************
check if a user is allowed to delete a file
********************************************************************/
-static BOOL can_delete(char *fname,int cnum,int dirtype)
+static BOOL can_delete(char *fname,connection_struct *conn, int dirtype)
{
- struct stat sbuf;
+ SMB_STRUCT_STAT sbuf;
int fmode;
- if (!CAN_WRITE(cnum)) return(False);
+ if (!CAN_WRITE(conn)) return(False);
- if (sys_lstat(fname,&sbuf) != 0) return(False);
- fmode = dos_mode(cnum,fname,&sbuf);
+ if (conn->vfs_ops.lstat(dos_to_unix(fname,False),&sbuf) != 0) return(False);
+ fmode = dos_mode(conn,fname,&sbuf);
if (fmode & aDIR) return(False);
- if (fmode & aRONLY) return(False);
+ if (!lp_delete_readonly(SNUM(conn))) {
+ if (fmode & aRONLY) return(False);
+ }
if ((fmode & ~dirtype) & (aHIDDEN | aSYSTEM))
return(False);
- if (!check_file_sharing(cnum,fname)) return(False);
+ if (!check_file_sharing(conn,fname,False)) return(False);
return(True);
}
/****************************************************************************
- reply to a unlink
+ Reply to a unlink
****************************************************************************/
-int reply_unlink(char *inbuf,char *outbuf)
+
+int reply_unlink(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
{
int outsize = 0;
pstring name;
- int cnum;
int dirtype;
pstring directory;
pstring mask;
@@ -1202,63 +1844,82 @@ int reply_unlink(char *inbuf,char *outbuf)
int error = ERRnoaccess;
BOOL has_wild;
BOOL exists=False;
+ BOOL bad_path = False;
+ BOOL rc = True;
*directory = *mask = 0;
- cnum = SVAL(inbuf,smb_tid);
dirtype = SVAL(inbuf,smb_vwv0);
- strcpy(name,smb_buf(inbuf) + 1);
+ pstrcpy(name,smb_buf(inbuf) + 1);
+ RESOLVE_DFSPATH(name, conn, inbuf, outbuf);
+
DEBUG(3,("reply_unlink : %s\n",name));
- unix_convert(name,cnum);
+ rc = unix_convert(name,conn,0,&bad_path,NULL);
p = strrchr(name,'/');
if (!p) {
- strcpy(directory,"./");
- strcpy(mask,name);
+ pstrcpy(directory,"./");
+ pstrcpy(mask,name);
} else {
*p = 0;
- strcpy(directory,name);
- strcpy(mask,p+1);
+ pstrcpy(directory,name);
+ pstrcpy(mask,p+1);
}
- if (is_mangled(mask))
- check_mangled_stack(mask);
+ /*
+ * We should only check the mangled cache
+ * here if unix_convert failed. This means
+ * that the path in 'mask' doesn't exist
+ * on the file system and so we need to look
+ * for a possible mangle. This patch from
+ * Tine Smukavec <valentin.smukavec@hermes.si>.
+ */
- has_wild = strchr(mask,'*') || strchr(mask,'?');
+ if (!rc && is_mangled(mask))
+ check_mangled_cache( mask );
+
+ has_wild = ms_has_wild(mask);
if (!has_wild) {
- strcat(directory,"/");
- strcat(directory,mask);
- if (can_delete(directory,cnum,dirtype) && !sys_unlink(directory)) count++;
- if (!count) exists = file_exist(directory,NULL);
+ pstrcat(directory,"/");
+ pstrcat(directory,mask);
+ if (can_delete(directory,conn,dirtype) && !vfs_unlink(conn,directory))
+ count++;
+ if (!count)
+ exists = vfs_file_exist(conn,directory,NULL);
} else {
void *dirptr = NULL;
char *dname;
- if (check_name(directory,cnum))
- dirptr = OpenDir(directory);
+ if (check_name(directory,conn))
+ dirptr = OpenDir(conn, directory, True);
+
+ /* XXXX the CIFS spec says that if bit0 of the flags2 field is set then
+ the pattern matches against the long name, otherwise the short name
+ We don't implement this yet XXXX
+ */
if (dirptr)
{
error = ERRbadfile;
if (strequal(mask,"????????.???"))
- strcpy(mask,"*");
+ pstrcpy(mask,"*");
while ((dname = ReadDirName(dirptr)))
{
pstring fname;
- strcpy(fname,dname);
+ pstrcpy(fname,dname);
- if(!mask_match(fname, mask, case_sensitive, False)) continue;
+ if(!mask_match(fname, mask, case_sensitive)) continue;
error = ERRnoaccess;
- sprintf(fname,"%s/%s",directory,dname);
- if (!can_delete(fname,cnum,dirtype)) continue;
- if (!sys_unlink(fname)) count++;
+ slprintf(fname,sizeof(fname)-1, "%s/%s",directory,dname);
+ if (!can_delete(fname,conn,dirtype)) continue;
+ if (!conn->vfs_ops.unlink(dos_to_unix(fname,False))) count++;
DEBUG(3,("reply_unlink : doing unlink on %s\n",fname));
}
CloseDir(dirptr);
@@ -1269,7 +1930,14 @@ int reply_unlink(char *inbuf,char *outbuf)
if (exists)
return(ERROR(ERRDOS,error));
else
+ {
+ if((errno == ENOENT) && bad_path)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
return(UNIXERROR(ERRDOS,error));
+ }
}
outsize = set_message(outbuf,0,0,True);
@@ -1281,91 +1949,141 @@ int reply_unlink(char *inbuf,char *outbuf)
/****************************************************************************
reply to a readbraw (core+ protocol)
****************************************************************************/
-int reply_readbraw(char *inbuf, char *outbuf)
+
+int reply_readbraw(connection_struct *conn, char *inbuf, char *outbuf, int dum_size, int dum_buffsize)
{
- int cnum,maxcount,mincount,fnum;
- int nread = 0;
- int startpos;
+ size_t maxcount,mincount;
+ size_t nread = 0;
+ SMB_OFF_T startpos;
char *header = outbuf;
- int ret=0;
- int fd;
- char *fname;
+ ssize_t ret=0;
+ files_struct *fsp;
- cnum = SVAL(inbuf,smb_tid);
- fnum = GETFNUM(inbuf,smb_vwv0);
+ /*
+ * Special check if an oplock break has been issued
+ * and the readraw request croses on the wire, we must
+ * return a zero length response here.
+ */
+
+ if(global_oplock_break)
+ {
+ _smb_setlen(header,0);
+ transfer_file(0,smbd_server_fd(),(SMB_OFF_T)0,header,4,0);
+ DEBUG(5,("readbraw - oplock break finished\n"));
+ return -1;
+ }
+
+ fsp = file_fsp(inbuf,smb_vwv0);
+
+ if (!FNUM_OK(fsp,conn) || !fsp->can_read) {
+ /*
+ * fsp could be NULL here so use the value from the packet. JRA.
+ */
+ DEBUG(3,("fnum %d not open in readbraw - cache prime?\n",(int)SVAL(inbuf,smb_vwv0)));
+ _smb_setlen(header,0);
+ transfer_file(0,smbd_server_fd(),(SMB_OFF_T)0,header,4,0);
+ return(-1);
+ }
+
+ CHECK_FSP(fsp,conn);
+
+ flush_write_cache(fsp, READRAW_FLUSH);
startpos = IVAL(inbuf,smb_vwv1);
- maxcount = SVAL(inbuf,smb_vwv3);
- mincount = SVAL(inbuf,smb_vwv4);
+ if(CVAL(inbuf,smb_wct) == 10) {
+ /*
+ * This is a large offset (64 bit) read.
+ */
+#ifdef LARGE_SMB_OFF_T
- /* ensure we don't overrun the packet size */
- maxcount = MIN(65535,maxcount);
- maxcount = MAX(mincount,maxcount);
+ startpos |= (((SMB_OFF_T)IVAL(inbuf,smb_vwv8)) << 32);
- if (!FNUM_OK(fnum,cnum) || !Files[fnum].can_read)
- {
- DEBUG(3,("fnum %d not open in readbraw - cache prime?\n",fnum));
+#else /* !LARGE_SMB_OFF_T */
+
+ /*
+ * Ensure we haven't been sent a >32 bit offset.
+ */
+
+ if(IVAL(inbuf,smb_vwv8) != 0) {
+ DEBUG(0,("readbraw - large offset (%x << 32) used and we don't support \
+64 bit offsets.\n", (unsigned int)IVAL(inbuf,smb_vwv8) ));
_smb_setlen(header,0);
- transfer_file(0,Client,0,header,4,0);
+ transfer_file(0,smbd_server_fd(),(SMB_OFF_T)0,header,4,0);
return(-1);
}
- else
- {
- fd = Files[fnum].fd;
- fname = Files[fnum].name;
- }
+#endif /* LARGE_SMB_OFF_T */
- if (!is_locked(fnum,cnum,maxcount,startpos))
- {
- int size = Files[fnum].size;
- int sizeneeded = startpos + maxcount;
-
- if (size < sizeneeded) {
- struct stat st;
- if (fstat(Files[fnum].fd,&st) == 0)
- size = st.st_size;
- if (!Files[fnum].can_write)
- Files[fnum].size = size;
- }
+ if(startpos < 0) {
+ DEBUG(0,("readbraw - negative 64 bit readraw offset (%.0f) !\n",
+ (double)startpos ));
+ _smb_setlen(header,0);
+ transfer_file(0,smbd_server_fd(),(SMB_OFF_T)0,header,4,0);
+ return(-1);
+ }
+ }
+ maxcount = (SVAL(inbuf,smb_vwv3) & 0xFFFF);
+ mincount = (SVAL(inbuf,smb_vwv4) & 0xFFFF);
+
+ /* ensure we don't overrun the packet size */
+ maxcount = MIN(65535,maxcount);
+ maxcount = MAX(mincount,maxcount);
- nread = MIN(maxcount,size - startpos);
+ if (!is_locked(fsp,conn,(SMB_BIG_UINT)maxcount,(SMB_BIG_UINT)startpos, READ_LOCK))
+ {
+ SMB_OFF_T size = fsp->size;
+ SMB_OFF_T sizeneeded = startpos + maxcount;
+
+ if (size < sizeneeded)
+ {
+ SMB_STRUCT_STAT st;
+ if (fsp->conn->vfs_ops.fstat(fsp->fd,&st) == 0)
+ size = st.st_size;
+ if (!fsp->can_write)
+ fsp->size = size;
}
+ nread = MIN(maxcount,(size - startpos));
+ }
+
if (nread < mincount)
nread = 0;
- DEBUG(3,("%s readbraw fnum=%d cnum=%d start=%d max=%d min=%d nread=%d\n",
- timestring(),
- fnum,cnum,startpos,
- maxcount,mincount,nread));
+ DEBUG( 3, ( "readbraw fnum=%d start=%.0f max=%d min=%d nread=%d\n",
+ fsp->fnum, (double)startpos,
+ (int)maxcount, (int)mincount, (int)nread ) );
#if UNSAFE_READRAW
{
+ BOOL seek_fail = False;
int predict=0;
_smb_setlen(header,nread);
- if (!Files[fnum].can_write)
- predict = read_predict(fd,startpos,header+4,NULL,nread);
+ if ((nread-predict) > 0) {
+ if(conn->vfs_ops.seek(fsp,startpos + predict) == -1) {
+ DEBUG(0,("reply_readbraw: ERROR: seek_file failed.\n"));
+ ret = 0;
+ seek_fail = True;
+ }
+ }
- if ((nread-predict) > 0)
- seek_file(fnum,startpos + predict);
-
- ret = transfer_file(fd,Client,nread-predict,header,4+predict,
- startpos+predict);
+ if(!seek_fail)
+ ret = (ssize_t)vfs_transfer_file(-1, fsp->fd, Client, NULL,
+ (SMB_OFF_T)(nread-predict),header,4+predict,
+ startpos+predict);
}
if (ret != nread+4)
DEBUG(0,("ERROR: file read failure on %s at %d for %d bytes (%d)\n",
- fname,startpos,nread,ret));
+ fsp->fsp_name,startpos,nread,ret));
-#else
- ret = read_file(fnum,header+4,startpos,nread,nread,-1,False);
+#else /* UNSAFE_READRAW */
+ ret = read_file(fsp,header+4,startpos,nread);
if (ret < mincount) ret = 0;
_smb_setlen(header,ret);
- transfer_file(0,Client,0,header,4+ret,0);
-#endif
+ transfer_file(0,smbd_server_fd(),0,header,4+ret,0);
+#endif /* UNSAFE_READRAW */
DEBUG(5,("readbraw finished\n"));
return -1;
@@ -1375,22 +2093,20 @@ int reply_readbraw(char *inbuf, char *outbuf)
/****************************************************************************
reply to a lockread (core+ protocol)
****************************************************************************/
-int reply_lockread(char *inbuf,char *outbuf)
+int reply_lockread(connection_struct *conn, char *inbuf,char *outbuf, int length, int dum_buffsiz)
{
- int cnum,fnum;
- int nread = -1;
+ ssize_t nread = -1;
char *data;
int outsize = 0;
- uint32 startpos, numtoread;
+ SMB_OFF_T startpos;
+ size_t numtoread;
int eclass;
uint32 ecode;
-
- cnum = SVAL(inbuf,smb_tid);
- fnum = GETFNUM(inbuf,smb_vwv0);
+ files_struct *fsp = file_fsp(inbuf,smb_vwv0);
- CHECK_FNUM(fnum,cnum);
- CHECK_READ(fnum);
- CHECK_ERROR(fnum);
+ CHECK_FSP(fsp,conn);
+ CHECK_READ(fsp);
+ CHECK_ERROR(fsp);
numtoread = SVAL(inbuf,smb_vwv1);
startpos = IVAL(inbuf,smb_vwv2);
@@ -1398,22 +2114,40 @@ int reply_lockread(char *inbuf,char *outbuf)
outsize = set_message(outbuf,5,3,True);
numtoread = MIN(BUFFER_SIZE-outsize,numtoread);
data = smb_buf(outbuf) + 3;
-
- if(!do_lock( fnum, cnum, numtoread, startpos, &eclass, &ecode))
+
+ /*
+ * NB. Discovered by Menny Hamburger at Mainsoft. This is a core+
+ * protocol request that predates the read/write lock concept.
+ * Thus instead of asking for a read lock here we need to ask
+ * for a write lock. JRA.
+ */
+
+ if(!do_lock( fsp, conn, (SMB_BIG_UINT)numtoread, (SMB_BIG_UINT)startpos, WRITE_LOCK, &eclass, &ecode)) {
+ if((ecode == ERRlock) && lp_blocking_locks(SNUM(conn))) {
+ /*
+ * A blocking lock was requested. Package up
+ * this smb into a queued request and push it
+ * onto the blocking lock queue.
+ */
+ if(push_blocking_lock_request(inbuf, length, -1, 0))
+ return -1;
+ }
return (ERROR(eclass,ecode));
+ }
+
+ nread = read_file(fsp,data,startpos,numtoread);
- nread = read_file(fnum,data,startpos,numtoread,numtoread,-1,False);
-
if (nread < 0)
return(UNIXERROR(ERRDOS,ERRnoaccess));
-
+
outsize += nread;
SSVAL(outbuf,smb_vwv0,nread);
SSVAL(outbuf,smb_vwv5,nread+3);
SSVAL(smb_buf(outbuf),1,nread);
-
- DEBUG(3,("%s lockread fnum=%d cnum=%d num=%d nread=%d\n",timestring(),fnum,cnum,numtoread,nread));
-
+
+ DEBUG( 3, ( "lockread fnum=%d num=%d nread=%d\n",
+ fsp->fnum, (int)numtoread, (int)nread ) );
+
return(outsize);
}
@@ -1421,20 +2155,19 @@ int reply_lockread(char *inbuf,char *outbuf)
/****************************************************************************
reply to a read
****************************************************************************/
-int reply_read(char *inbuf,char *outbuf)
+
+int reply_read(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
{
- int cnum,numtoread,fnum;
- int nread = 0;
+ size_t numtoread;
+ ssize_t nread = 0;
char *data;
- int startpos;
+ SMB_OFF_T startpos;
int outsize = 0;
-
- cnum = SVAL(inbuf,smb_tid);
- fnum = GETFNUM(inbuf,smb_vwv0);
+ files_struct *fsp = file_fsp(inbuf,smb_vwv0);
- CHECK_FNUM(fnum,cnum);
- CHECK_READ(fnum);
- CHECK_ERROR(fnum);
+ CHECK_FSP(fsp,conn);
+ CHECK_READ(fsp);
+ CHECK_ERROR(fsp);
numtoread = SVAL(inbuf,smb_vwv1);
startpos = IVAL(inbuf,smb_vwv2);
@@ -1443,11 +2176,11 @@ int reply_read(char *inbuf,char *outbuf)
numtoread = MIN(BUFFER_SIZE-outsize,numtoread);
data = smb_buf(outbuf) + 3;
- if (is_locked(fnum,cnum,numtoread,startpos))
+ if (is_locked(fsp,conn,(SMB_BIG_UINT)numtoread,(SMB_BIG_UINT)startpos, READ_LOCK))
return(ERROR(ERRDOS,ERRlock));
if (numtoread > 0)
- nread = read_file(fnum,data,startpos,numtoread,numtoread,-1,False);
+ nread = read_file(fsp,data,startpos,numtoread);
if (nread < 0)
return(UNIXERROR(ERRDOS,ERRnoaccess));
@@ -1458,8 +2191,9 @@ int reply_read(char *inbuf,char *outbuf)
CVAL(smb_buf(outbuf),0) = 1;
SSVAL(smb_buf(outbuf),1,nread);
- DEBUG(3,("%s read fnum=%d cnum=%d num=%d nread=%d\n",timestring(),fnum,cnum,numtoread,nread));
-
+ DEBUG( 3, ( "read fnum=%d num=%d nread=%d\n",
+ fsp->fnum, (int)numtoread, (int)nread ) );
+
return(outsize);
}
@@ -1467,82 +2201,85 @@ int reply_read(char *inbuf,char *outbuf)
/****************************************************************************
reply to a read and X
****************************************************************************/
-int reply_read_and_X(char *inbuf,char *outbuf,int length,int bufsize)
-{
- int smb_com2 = CVAL(inbuf,smb_vwv0);
- int smb_off2 = SVAL(inbuf,smb_vwv1);
- int fnum = GETFNUM(inbuf,smb_vwv2);
- uint32 smb_offs = IVAL(inbuf,smb_vwv3);
- int smb_maxcnt = SVAL(inbuf,smb_vwv5);
- int smb_mincnt = SVAL(inbuf,smb_vwv6);
- int cnum;
- int nread = -1;
+int reply_read_and_X(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
+{
+ files_struct *fsp = file_fsp(inbuf,smb_vwv2);
+ SMB_OFF_T startpos = IVAL(inbuf,smb_vwv3);
+ size_t smb_maxcnt = SVAL(inbuf,smb_vwv5);
+ size_t smb_mincnt = SVAL(inbuf,smb_vwv6);
+ ssize_t nread = -1;
char *data;
- int outsize = 0;
- BOOL ok = False;
- cnum = SVAL(inbuf,smb_tid);
+ /* If it's an IPC, pass off the pipe handler. */
+ if (IS_IPC(conn))
+ return reply_pipe_read_and_X(inbuf,outbuf,length,bufsize);
- CHECK_FNUM(fnum,cnum);
- CHECK_READ(fnum);
- CHECK_ERROR(fnum);
+ CHECK_FSP(fsp,conn);
+ CHECK_READ(fsp);
+ CHECK_ERROR(fsp);
- outsize = set_message(outbuf,12,0,True);
+ set_message(outbuf,12,0,True);
data = smb_buf(outbuf);
- if (is_locked(fnum,cnum,smb_maxcnt,smb_offs))
+ if(CVAL(inbuf,smb_wct) == 12) {
+#ifdef LARGE_SMB_OFF_T
+ /*
+ * This is a large offset (64 bit) read.
+ */
+ startpos |= (((SMB_OFF_T)IVAL(inbuf,smb_vwv10)) << 32);
+
+#else /* !LARGE_SMB_OFF_T */
+
+ /*
+ * Ensure we haven't been sent a >32 bit offset.
+ */
+
+ if(IVAL(inbuf,smb_vwv10) != 0) {
+ DEBUG(0,("reply_read_and_X - large offset (%x << 32) used and we don't support \
+64 bit offsets.\n", (unsigned int)IVAL(inbuf,smb_vwv10) ));
+ return(ERROR(ERRDOS,ERRbadaccess));
+ }
+
+#endif /* LARGE_SMB_OFF_T */
+
+ }
+
+ if (is_locked(fsp,conn,(SMB_BIG_UINT)smb_maxcnt,(SMB_BIG_UINT)startpos, READ_LOCK))
return(ERROR(ERRDOS,ERRlock));
- nread = read_file(fnum,data,smb_offs,smb_maxcnt,smb_maxcnt,-1,False);
- ok = True;
+ nread = read_file(fsp,data,startpos,smb_maxcnt);
if (nread < 0)
return(UNIXERROR(ERRDOS,ERRnoaccess));
- outsize += nread;
- CVAL(outbuf,smb_vwv0) = smb_com2;
- SSVAL(outbuf,smb_vwv1,(outsize+chain_size)-4);
SSVAL(outbuf,smb_vwv5,nread);
- SSVAL(outbuf,smb_vwv6,smb_offset(data,outbuf) + chain_size);
+ SSVAL(outbuf,smb_vwv6,smb_offset(data,outbuf));
SSVAL(smb_buf(outbuf),-2,nread);
- DEBUG(3,("%s readX fnum=%d cnum=%d min=%d max=%d nread=%d com2=%d off2=%d\n",
- timestring(),fnum,cnum,
- smb_mincnt,smb_maxcnt,nread,smb_com2,smb_off2));
-
- chain_fnum = fnum;
+ DEBUG( 3, ( "readX fnum=%d min=%d max=%d nread=%d\n",
+ fsp->fnum, (int)smb_mincnt, (int)smb_maxcnt, (int)nread ) );
- if (smb_com2 != 0xFF)
- outsize += chain_reply(smb_com2,inbuf,inbuf+smb_off2+4,
- outbuf,outbuf+outsize,
- length,bufsize);
-
- chain_fnum = -1;
-
- return(outsize);
+ return chain_reply(inbuf,outbuf,length,bufsize);
}
-
/****************************************************************************
reply to a writebraw (core+ or LANMAN1.0 protocol)
****************************************************************************/
-int reply_writebraw(char *inbuf,char *outbuf)
+
+int reply_writebraw(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
{
- int nwritten=0;
- int total_written=0;
- int numtowrite=0;
- int cnum,fnum;
- int outsize = 0;
- long startpos;
+ ssize_t nwritten=0;
+ ssize_t total_written=0;
+ size_t numtowrite=0;
+ size_t tcount;
+ SMB_OFF_T startpos;
char *data=NULL;
BOOL write_through;
- int tcount;
-
- cnum = SVAL(inbuf,smb_tid);
- fnum = GETFNUM(inbuf,smb_vwv0);
+ files_struct *fsp = file_fsp(inbuf,smb_vwv0);
+ int outsize = 0;
- CHECK_FNUM(fnum,cnum);
- CHECK_WRITE(fnum);
- CHECK_ERROR(fnum);
+ CHECK_FSP(fsp,conn);
+ CHECK_WRITE(fsp);
+ CHECK_ERROR(fsp);
tcount = IVAL(inbuf,smb_vwv1);
startpos = IVAL(inbuf,smb_vwv3);
@@ -1562,17 +2299,14 @@ int reply_writebraw(char *inbuf,char *outbuf)
CVAL(inbuf,smb_com) = SMBwritec;
CVAL(outbuf,smb_com) = SMBwritec;
- if (is_locked(fnum,cnum,tcount,startpos))
+ if (is_locked(fsp,conn,(SMB_BIG_UINT)tcount,(SMB_BIG_UINT)startpos, WRITE_LOCK))
return(ERROR(ERRDOS,ERRlock));
- if (seek_file(fnum,startpos) != startpos)
- DEBUG(0,("couldn't seek to %d in writebraw\n",startpos));
-
if (numtowrite>0)
- nwritten = write_file(fnum,data,numtowrite);
+ nwritten = write_file(fsp,data,startpos,numtowrite);
- DEBUG(3,("%s writebraw1 fnum=%d cnum=%d start=%d num=%d wrote=%d sync=%d\n",
- timestring(),fnum,cnum,startpos,numtowrite,nwritten,write_through));
+ DEBUG(3,("writebraw1 fnum=%d start=%.0f num=%d wrote=%d sync=%d\n",
+ fsp->fnum, (double)startpos, (int)numtowrite, (int)nwritten, (int)write_through));
if (nwritten < numtowrite)
return(UNIXERROR(ERRHRD,ERRdiskfull));
@@ -1584,10 +2318,10 @@ int reply_writebraw(char *inbuf,char *outbuf)
CVAL(outbuf,smb_com) = SMBwritebraw;
SSVALS(outbuf,smb_vwv0,-1);
outsize = set_message(outbuf,Protocol>PROTOCOL_COREPLUS?1:0,0,True);
- send_smb(Client,outbuf);
+ send_smb(smbd_server_fd(),outbuf);
/* Now read the raw data into the buffer and write it */
- if(read_smb_length(Client,inbuf,0) == -1) {
+ if (read_smb_length(smbd_server_fd(),inbuf,SMB_SECONDARY_WAIT) == -1) {
exit_server("secondary writebraw failed");
}
@@ -1597,11 +2331,12 @@ int reply_writebraw(char *inbuf,char *outbuf)
if (tcount > nwritten+numtowrite) {
DEBUG(3,("Client overestimated the write %d %d %d\n",
- tcount,nwritten,numtowrite));
+ (int)tcount,(int)nwritten,(int)numtowrite));
}
- nwritten = transfer_file(Client,Files[fnum].fd,numtowrite,NULL,0,
- startpos+nwritten);
+ nwritten = vfs_transfer_file(smbd_server_fd(), NULL, -1, fsp,
+ (SMB_OFF_T)numtowrite,NULL,0,
+ startpos+nwritten);
total_written += nwritten;
/* Set up outbuf to return the correct return */
@@ -1609,16 +2344,17 @@ int reply_writebraw(char *inbuf,char *outbuf)
CVAL(outbuf,smb_com) = SMBwritec;
SSVAL(outbuf,smb_vwv0,total_written);
- if (nwritten < numtowrite) {
+ if (nwritten < (ssize_t)numtowrite) {
CVAL(outbuf,smb_rcls) = ERRHRD;
SSVAL(outbuf,smb_err,ERRdiskfull);
}
- if (lp_syncalways(SNUM(cnum)) || write_through)
- sync_file(fnum);
+ if ((lp_syncalways(SNUM(conn)) || write_through) &&
+ lp_strict_sync(SNUM(conn)))
+ sync_file(conn,fsp);
- DEBUG(3,("%s writebraw2 fnum=%d cnum=%d start=%d num=%d wrote=%d\n",
- timestring(),fnum,cnum,startpos,numtowrite,total_written));
+ DEBUG(3,("writebraw2 fnum=%d start=%.0f num=%d wrote=%d\n",
+ fsp->fnum, (double)startpos, (int)numtowrite,(int)total_written));
/* we won't return a status if write through is not selected - this
follows what WfWg does */
@@ -1628,104 +2364,97 @@ int reply_writebraw(char *inbuf,char *outbuf)
return(outsize);
}
-
/****************************************************************************
reply to a writeunlock (core+)
****************************************************************************/
-int reply_writeunlock(char *inbuf,char *outbuf)
+
+int reply_writeunlock(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
{
- int cnum,fnum;
- int nwritten = -1;
- int outsize = 0;
+ ssize_t nwritten = -1;
+ size_t numtowrite;
+ SMB_OFF_T startpos;
char *data;
- uint32 numtowrite,startpos;
int eclass;
uint32 ecode;
-
- cnum = SVAL(inbuf,smb_tid);
- fnum = GETFNUM(inbuf,smb_vwv0);
+ files_struct *fsp = file_fsp(inbuf,smb_vwv0);
+ int outsize = 0;
- CHECK_FNUM(fnum,cnum);
- CHECK_WRITE(fnum);
- CHECK_ERROR(fnum);
+ CHECK_FSP(fsp,conn);
+ CHECK_WRITE(fsp);
+ CHECK_ERROR(fsp);
numtowrite = SVAL(inbuf,smb_vwv1);
startpos = IVAL(inbuf,smb_vwv2);
data = smb_buf(inbuf) + 3;
- if (is_locked(fnum,cnum,numtowrite,startpos))
+ if (is_locked(fsp,conn,(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, WRITE_LOCK))
return(ERROR(ERRDOS,ERRlock));
- seek_file(fnum,startpos);
-
/* The special X/Open SMB protocol handling of
zero length writes is *NOT* done for
this call */
if(numtowrite == 0)
nwritten = 0;
else
- nwritten = write_file(fnum,data,numtowrite);
+ nwritten = write_file(fsp,data,startpos,numtowrite);
- if (lp_syncalways(SNUM(cnum)))
- sync_file(fnum);
+ if (lp_syncalways(SNUM(conn)))
+ sync_file(conn,fsp);
if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0))
return(UNIXERROR(ERRDOS,ERRnoaccess));
- if(!do_unlock(fnum, cnum, numtowrite, startpos, &eclass, &ecode))
+ if(!do_unlock(fsp, conn, (SMB_BIG_UINT)numtowrite, (SMB_BIG_UINT)startpos, &eclass, &ecode))
return(ERROR(eclass,ecode));
outsize = set_message(outbuf,1,0,True);
SSVAL(outbuf,smb_vwv0,nwritten);
- DEBUG(3,("%s writeunlock fnum=%d cnum=%d num=%d wrote=%d\n",
- timestring(),fnum,cnum,numtowrite,nwritten));
-
+ DEBUG( 3, ( "writeunlock fnum=%d num=%d wrote=%d\n",
+ fsp->fnum, (int)numtowrite, (int)nwritten ) );
+
return(outsize);
}
-
/****************************************************************************
reply to a write
****************************************************************************/
-int reply_write(char *inbuf,char *outbuf,int dum1,int dum2)
+int reply_write(connection_struct *conn, char *inbuf,char *outbuf,int size,int dum_buffsize)
{
- int cnum,numtowrite,fnum;
- int nwritten = -1;
- int outsize = 0;
- int startpos;
+ size_t numtowrite;
+ ssize_t nwritten = -1;
+ SMB_OFF_T startpos;
char *data;
+ files_struct *fsp = file_fsp(inbuf,smb_vwv0);
+ int outsize = 0;
- dum1 = dum2 = 0;
+ /* If it's an IPC, pass off the pipe handler. */
+ if (IS_IPC(conn))
+ return reply_pipe_write(inbuf,outbuf,size,dum_buffsize);
-
- cnum = SVAL(inbuf,smb_tid);
- fnum = GETFNUM(inbuf,smb_vwv0);
-
- CHECK_FNUM(fnum,cnum);
- CHECK_WRITE(fnum);
- CHECK_ERROR(fnum);
+ CHECK_FSP(fsp,conn);
+ CHECK_WRITE(fsp);
+ CHECK_ERROR(fsp);
numtowrite = SVAL(inbuf,smb_vwv1);
startpos = IVAL(inbuf,smb_vwv2);
data = smb_buf(inbuf) + 3;
- if (is_locked(fnum,cnum,numtowrite,startpos))
+ if (is_locked(fsp,conn,(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, WRITE_LOCK))
return(ERROR(ERRDOS,ERRlock));
- seek_file(fnum,startpos);
-
/* X/Open SMB protocol says that if smb_vwv1 is
zero then the file size should be extended or
truncated to the size given in smb_vwv[2-3] */
- if(numtowrite == 0)
- nwritten = set_filelen(Files[fnum].fd, startpos);
- else
- nwritten = write_file(fnum,data,numtowrite);
+ if(numtowrite == 0) {
+ if((nwritten = set_filelen(fsp->fd, (SMB_OFF_T)startpos)) >= 0) /* tpot vfs */
+ set_filelen_write_cache(fsp, startpos);
+ } else
+ nwritten = write_file(fsp,data,startpos,numtowrite);
- if (lp_syncalways(SNUM(cnum)))
- sync_file(fnum);
+ if (lp_syncalways(SNUM(conn)))
+ sync_file(conn,fsp);
if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0))
return(UNIXERROR(ERRDOS,ERRnoaccess));
@@ -1734,13 +2463,14 @@ int reply_write(char *inbuf,char *outbuf,int dum1,int dum2)
SSVAL(outbuf,smb_vwv0,nwritten);
- if (nwritten < numtowrite) {
+ if (nwritten < (ssize_t)numtowrite) {
CVAL(outbuf,smb_rcls) = ERRHRD;
SSVAL(outbuf,smb_err,ERRdiskfull);
}
- DEBUG(3,("%s write fnum=%d cnum=%d num=%d wrote=%d\n",timestring(),fnum,cnum,numtowrite,nwritten));
-
+ DEBUG(3,("write fnum=%d num=%d wrote=%d\n",
+ fsp->fnum, (int)numtowrite, (int)nwritten));
+
return(outsize);
}
@@ -1748,142 +2478,180 @@ int reply_write(char *inbuf,char *outbuf,int dum1,int dum2)
/****************************************************************************
reply to a write and X
****************************************************************************/
-int reply_write_and_X(char *inbuf,char *outbuf,int length,int bufsize)
-{
- int smb_com2 = CVAL(inbuf,smb_vwv0);
- int smb_off2 = SVAL(inbuf,smb_vwv1);
- int fnum = GETFNUM(inbuf,smb_vwv2);
- uint32 smb_offs = IVAL(inbuf,smb_vwv3);
- int smb_dsize = SVAL(inbuf,smb_vwv10);
- int smb_doff = SVAL(inbuf,smb_vwv11);
+int reply_write_and_X(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
+{
+ files_struct *fsp = file_fsp(inbuf,smb_vwv2);
+ SMB_OFF_T startpos = IVAL(inbuf,smb_vwv3);
+ size_t numtowrite = SVAL(inbuf,smb_vwv10);
BOOL write_through = BITSETW(inbuf+smb_vwv7,0);
- int cnum;
- int nwritten = -1;
- int outsize = 0;
+ ssize_t nwritten = -1;
+ unsigned int smb_doff = SVAL(inbuf,smb_vwv11);
char *data;
- cnum = SVAL(inbuf,smb_tid);
+ /* If it's an IPC, pass off the pipe handler. */
+ if (IS_IPC(conn))
+ return reply_pipe_write_and_X(inbuf,outbuf,length,bufsize);
- CHECK_FNUM(fnum,cnum);
- CHECK_WRITE(fnum);
- CHECK_ERROR(fnum);
+ CHECK_FSP(fsp,conn);
+ CHECK_WRITE(fsp);
+ CHECK_ERROR(fsp);
+
+ if(smb_doff > smb_len(inbuf))
+ return(ERROR(ERRDOS,ERRbadmem));
data = smb_base(inbuf) + smb_doff;
- if (is_locked(fnum,cnum,smb_dsize,smb_offs))
+ if(CVAL(inbuf,smb_wct) == 14) {
+#ifdef LARGE_SMB_OFF_T
+ /*
+ * This is a large offset (64 bit) write.
+ */
+ startpos |= (((SMB_OFF_T)IVAL(inbuf,smb_vwv12)) << 32);
+
+#else /* !LARGE_SMB_OFF_T */
+
+ /*
+ * Ensure we haven't been sent a >32 bit offset.
+ */
+
+ if(IVAL(inbuf,smb_vwv12) != 0) {
+ DEBUG(0,("reply_write_and_X - large offset (%x << 32) used and we don't support \
+64 bit offsets.\n", (unsigned int)IVAL(inbuf,smb_vwv12) ));
+ return(ERROR(ERRDOS,ERRbadaccess));
+ }
+
+#endif /* LARGE_SMB_OFF_T */
+ }
+
+ if (is_locked(fsp,conn,(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, WRITE_LOCK))
return(ERROR(ERRDOS,ERRlock));
- seek_file(fnum,smb_offs);
-
/* X/Open SMB protocol says that, unlike SMBwrite
if the length is zero then NO truncation is
done, just a write of zero. To truncate a file,
use SMBwrite. */
- if(smb_dsize == 0)
+ if(numtowrite == 0)
nwritten = 0;
else
- nwritten = write_file(fnum,data,smb_dsize);
+ nwritten = write_file(fsp,data,startpos,numtowrite);
- if(((nwritten == 0) && (smb_dsize != 0))||(nwritten < 0))
+ if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0))
return(UNIXERROR(ERRDOS,ERRnoaccess));
- outsize = set_message(outbuf,6,0,True);
+ set_message(outbuf,6,0,True);
- CVAL(outbuf,smb_vwv0) = smb_com2;
- SSVAL(outbuf,smb_vwv1,(outsize+chain_size)-4);
SSVAL(outbuf,smb_vwv2,nwritten);
- if (nwritten < smb_dsize) {
+ if (nwritten < (ssize_t)numtowrite) {
CVAL(outbuf,smb_rcls) = ERRHRD;
SSVAL(outbuf,smb_err,ERRdiskfull);
}
- DEBUG(3,("%s writeX fnum=%d cnum=%d num=%d wrote=%d\n",timestring(),fnum,cnum,smb_dsize,nwritten));
+ DEBUG(3,("writeX fnum=%d num=%d wrote=%d\n",
+ fsp->fnum, (int)numtowrite, (int)nwritten));
- chain_fnum = fnum;
+ if (lp_syncalways(SNUM(conn)) || write_through)
+ sync_file(conn,fsp);
- if (lp_syncalways(SNUM(cnum)) || write_through)
- sync_file(fnum);
-
- if (smb_com2 != 0xFF)
- outsize += chain_reply(smb_com2,inbuf,inbuf+smb_off2+4,
- outbuf,outbuf+outsize,
- length,bufsize);
-
- chain_fnum = -1;
-
- return(outsize);
+ return chain_reply(inbuf,outbuf,length,bufsize);
}
/****************************************************************************
reply to a lseek
****************************************************************************/
-int reply_lseek(char *inbuf,char *outbuf)
+
+int reply_lseek(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
{
- int cnum,fnum;
- uint32 startpos;
- int32 res= -1;
+ SMB_OFF_T startpos;
+ SMB_OFF_T res= -1;
int mode,umode;
int outsize = 0;
-
- cnum = SVAL(inbuf,smb_tid);
- fnum = GETFNUM(inbuf,smb_vwv0);
+ files_struct *fsp = file_fsp(inbuf,smb_vwv0);
- CHECK_FNUM(fnum,cnum);
- CHECK_ERROR(fnum);
+ CHECK_FSP(fsp,conn);
+ CHECK_ERROR(fsp);
+
+ flush_write_cache(fsp, SEEK_FLUSH);
mode = SVAL(inbuf,smb_vwv1) & 3;
- startpos = IVAL(inbuf,smb_vwv2);
+ startpos = IVALS(inbuf,smb_vwv2);
- switch (mode & 3)
- {
+ switch (mode) {
case 0: umode = SEEK_SET; break;
case 1: umode = SEEK_CUR; break;
case 2: umode = SEEK_END; break;
default:
umode = SEEK_SET; break;
+ }
+
+ if((res = conn->vfs_ops.lseek(fsp->fd,startpos,umode)) == -1) {
+ /*
+ * Check for the special case where a seek before the start
+ * of the file sets the offset to zero. Added in the CIFS spec,
+ * section 4.2.7.
+ */
+
+ if(errno == EINVAL) {
+ SMB_OFF_T current_pos = startpos;
+
+ if(umode == SEEK_CUR) {
+
+ if((current_pos = conn->vfs_ops.lseek(fsp->fd,0,SEEK_CUR)) == -1)
+ return(UNIXERROR(ERRDOS,ERRnoaccess));
+
+ current_pos += startpos;
+
+ } else if (umode == SEEK_END) {
+
+ SMB_STRUCT_STAT sbuf;
+
+ if(conn->vfs_ops.fstat(fsp->fd, &sbuf) == -1)
+ return(UNIXERROR(ERRDOS,ERRnoaccess));
+
+ current_pos += sbuf.st_size;
+ }
+
+ if(current_pos < 0)
+ res = conn->vfs_ops.lseek(fsp->fd,0,SEEK_SET);
}
-
- res = lseek(Files[fnum].fd,startpos,umode);
- Files[fnum].pos = res;
+
+ if(res == -1)
+ return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
+
+ fsp->pos = res;
outsize = set_message(outbuf,2,0,True);
- SIVALS(outbuf,smb_vwv0,res);
-
- DEBUG(3,("%s lseek fnum=%d cnum=%d ofs=%d mode=%d\n",timestring(),fnum,cnum,startpos,mode));
+ SIVAL(outbuf,smb_vwv0,res);
+ DEBUG(3,("lseek fnum=%d ofs=%.0f newpos = %.0f mode=%d\n",
+ fsp->fnum, (double)startpos, (double)res, mode));
+
return(outsize);
}
-
/****************************************************************************
reply to a flush
****************************************************************************/
-int reply_flush(char *inbuf,char *outbuf)
+
+int reply_flush(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
{
- int cnum, fnum;
int outsize = set_message(outbuf,0,0,True);
+ files_struct *fsp = file_fsp(inbuf,smb_vwv0);
- cnum = SVAL(inbuf,smb_tid);
- fnum = GETFNUM(inbuf,smb_vwv0);
-
- if (fnum != 0xFFFF) {
- CHECK_FNUM(fnum,cnum);
- CHECK_ERROR(fnum);
+ if (fsp) {
+ CHECK_FSP(fsp,conn);
+ CHECK_ERROR(fsp);
}
- if (fnum == 0xFFFF)
- {
- int i;
- for (i=0;i<MAX_OPEN_FILES;i++)
- if (OPEN_FNUM(i))
- sync_file(i);
- }
- else
- sync_file(fnum);
+ if (!fsp) {
+ file_sync_all(conn);
+ } else {
+ sync_file(conn,fsp);
+ }
- DEBUG(3,("%s flush fnum=%d\n",timestring(),fnum));
+ DEBUG(3,("flush\n"));
return(outsize);
}
@@ -1891,158 +2659,212 @@ int reply_flush(char *inbuf,char *outbuf)
/****************************************************************************
reply to a exit
****************************************************************************/
-int reply_exit(char *inbuf,char *outbuf)
+int reply_exit(connection_struct *conn,
+ char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
{
- int outsize = set_message(outbuf,0,0,True);
- DEBUG(3,("%s exit\n",timestring()));
-
- return(outsize);
+ int outsize = set_message(outbuf,0,0,True);
+ DEBUG(3,("exit\n"));
+
+ return(outsize);
}
/****************************************************************************
- reply to a close
+ Reply to a close - has to deal with closing a directory opened by NT SMB's.
****************************************************************************/
-int reply_close(char *inbuf,char *outbuf)
+int reply_close(connection_struct *conn, char *inbuf,char *outbuf, int size,
+ int dum_buffsize)
{
- int fnum,cnum;
- int outsize = 0;
- time_t mtime;
- int32 eclass = 0, err = 0;
+ int outsize = 0;
+ time_t mtime;
+ int32 eclass = 0, err = 0;
+ files_struct *fsp = NULL;
- outsize = set_message(outbuf,0,0,True);
+ outsize = set_message(outbuf,0,0,True);
- cnum = SVAL(inbuf,smb_tid);
+ /* If it's an IPC, pass off to the pipe handler. */
+ if (IS_IPC(conn))
+ return reply_pipe_close(conn, inbuf,outbuf);
- fnum = GETFNUM(inbuf,smb_vwv0);
- CHECK_FNUM(fnum,cnum);
+ fsp = file_fsp(inbuf,smb_vwv0);
- if(HAS_CACHED_ERROR(fnum)) {
- eclass = Files[fnum].wbmpx_ptr->wr_errclass;
- err = Files[fnum].wbmpx_ptr->wr_error;
- }
+ /*
+ * We can only use CHECK_FSP if we know it's not a directory.
+ */
- mtime = make_unix_date3(inbuf+smb_vwv1);
+ if(!fsp || (fsp->conn != conn))
+ return(ERROR(ERRDOS,ERRbadfid));
- close_file(fnum);
+ if(HAS_CACHED_ERROR(fsp)) {
+ eclass = fsp->wbmpx_ptr->wr_errclass;
+ err = fsp->wbmpx_ptr->wr_error;
+ }
- /* try and set the date */
- set_filetime(Files[fnum].name,mtime);
+ if(fsp->is_directory || fsp->stat_open) {
+ /*
+ * Special case - close NT SMB directory or stat file
+ * handle.
+ */
+ DEBUG(3,("close %s fnum=%d\n", fsp->is_directory ? "directory" : "stat file open", fsp->fnum));
+ close_file(fsp,True);
+ } else {
+ /*
+ * Close ordinary file.
+ */
+ int close_err;
+
+ /*
+ * If there was a modify time outstanding,
+ * try and set it here.
+ */
+ if(fsp->pending_modtime)
+ set_filetime(conn, fsp->fsp_name, fsp->pending_modtime);
+
+ /*
+ * Now take care of any time sent in the close.
+ */
+ mtime = make_unix_date3(inbuf+smb_vwv1);
+
+ /* try and set the date */
+ set_filetime(conn, fsp->fsp_name,mtime);
+
+ DEBUG(3,("close fd=%d fnum=%d (numopen=%d)\n",
+ fsp->fd, fsp->fnum,
+ conn->num_files_open));
+
+ /*
+ * close_file() returns the unix errno if an error
+ * was detected on close - normally this is due to
+ * a disk full error. If not then it was probably an I/O error.
+ */
+
+ if((close_err = close_file(fsp,True)) != 0) {
+ errno = close_err;
+ return (UNIXERROR(ERRHRD,ERRgeneral));
+ }
+ }
- /* We have a cached error */
- if(eclass || err)
- return(ERROR(eclass,err));
+ /* We have a cached error */
+ if(eclass || err)
+ return(ERROR(eclass,err));
- DEBUG(3,("%s close fd=%d fnum=%d cnum=%d (numopen=%d)\n",
- timestring(),Files[fnum].fd,fnum,cnum,
- Connections[cnum].num_files_open));
-
- return(outsize);
+ return(outsize);
}
/****************************************************************************
reply to a writeclose (Core+ protocol)
****************************************************************************/
-int reply_writeclose(char *inbuf,char *outbuf)
-{
- int cnum,numtowrite,fnum;
- int nwritten = -1;
- int outsize = 0;
- int startpos;
- char *data;
- time_t mtime;
-
- cnum = SVAL(inbuf,smb_tid);
- fnum = GETFNUM(inbuf,smb_vwv0);
- CHECK_FNUM(fnum,cnum);
- CHECK_WRITE(fnum);
- CHECK_ERROR(fnum);
-
- numtowrite = SVAL(inbuf,smb_vwv1);
- startpos = IVAL(inbuf,smb_vwv2);
- mtime = make_unix_date3(inbuf+smb_vwv4);
- data = smb_buf(inbuf) + 1;
-
- if (is_locked(fnum,cnum,numtowrite,startpos))
- return(ERROR(ERRDOS,ERRlock));
-
- seek_file(fnum,startpos);
-
- nwritten = write_file(fnum,data,numtowrite);
-
- close_file(fnum);
-
- set_filetime(Files[fnum].name,mtime);
-
- DEBUG(3,("%s writeclose fnum=%d cnum=%d num=%d wrote=%d (numopen=%d)\n",
- timestring(),fnum,cnum,numtowrite,nwritten,
- Connections[cnum].num_files_open));
-
- if (nwritten <= 0)
- return(UNIXERROR(ERRDOS,ERRnoaccess));
-
- outsize = set_message(outbuf,1,0,True);
+int reply_writeclose(connection_struct *conn,
+ char *inbuf,char *outbuf, int size, int dum_buffsize)
+{
+ size_t numtowrite;
+ ssize_t nwritten = -1;
+ int outsize = 0;
+ int close_err = 0;
+ SMB_OFF_T startpos;
+ char *data;
+ time_t mtime;
+ files_struct *fsp = file_fsp(inbuf,smb_vwv0);
+
+ CHECK_FSP(fsp,conn);
+ CHECK_WRITE(fsp);
+ CHECK_ERROR(fsp);
+
+ numtowrite = SVAL(inbuf,smb_vwv1);
+ startpos = IVAL(inbuf,smb_vwv2);
+ mtime = make_unix_date3(inbuf+smb_vwv4);
+ data = smb_buf(inbuf) + 1;
+
+ if (is_locked(fsp,conn,(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, WRITE_LOCK))
+ return(ERROR(ERRDOS,ERRlock));
+
+ nwritten = write_file(fsp,data,startpos,numtowrite);
+
+ set_filetime(conn, fsp->fsp_name,mtime);
+
+ close_err = close_file(fsp,True);
+
+ DEBUG(3,("writeclose fnum=%d num=%d wrote=%d (numopen=%d)\n",
+ fsp->fnum, (int)numtowrite, (int)nwritten,
+ conn->num_files_open));
+
+ if (nwritten <= 0)
+ return(UNIXERROR(ERRDOS,ERRnoaccess));
+
+ if(close_err != 0) {
+ errno = close_err;
+ return(UNIXERROR(ERRHRD,ERRgeneral));
+ }
+
+ outsize = set_message(outbuf,1,0,True);
- SSVAL(outbuf,smb_vwv0,nwritten);
- return(outsize);
+ SSVAL(outbuf,smb_vwv0,nwritten);
+ return(outsize);
}
/****************************************************************************
reply to a lock
****************************************************************************/
-int reply_lock(char *inbuf,char *outbuf)
+int reply_lock(connection_struct *conn,
+ char *inbuf,char *outbuf, int length, int dum_buffsize)
{
- int fnum,cnum;
- int outsize = set_message(outbuf,0,0,True);
- uint32 count,offset;
- int eclass;
- uint32 ecode;
-
- cnum = SVAL(inbuf,smb_tid);
- fnum = GETFNUM(inbuf,smb_vwv0);
-
- CHECK_FNUM(fnum,cnum);
- CHECK_ERROR(fnum);
-
- count = IVAL(inbuf,smb_vwv1);
- offset = IVAL(inbuf,smb_vwv3);
-
- DEBUG(3,("%s lock fd=%d fnum=%d cnum=%d ofs=%d cnt=%d\n",timestring(),Files[fnum].fd,fnum,cnum,offset,count));
+ int outsize = set_message(outbuf,0,0,True);
+ SMB_BIG_UINT count,offset;
+ int eclass;
+ uint32 ecode;
+ files_struct *fsp = file_fsp(inbuf,smb_vwv0);
+
+ CHECK_FSP(fsp,conn);
+ CHECK_ERROR(fsp);
+
+ count = (SMB_BIG_UINT)IVAL(inbuf,smb_vwv1);
+ offset = (SMB_BIG_UINT)IVAL(inbuf,smb_vwv3);
+
+ DEBUG(3,("lock fd=%d fnum=%d offset=%.0f count=%.0f\n",
+ fsp->fd, fsp->fnum, (double)offset, (double)count));
+
+ if (!do_lock(fsp, conn, count, offset, WRITE_LOCK, &eclass, &ecode)) {
+ if((ecode == ERRlock) && lp_blocking_locks(SNUM(conn))) {
+ /*
+ * A blocking lock was requested. Package up
+ * this smb into a queued request and push it
+ * onto the blocking lock queue.
+ */
+ if(push_blocking_lock_request(inbuf, length, -1, 0))
+ return -1;
+ }
+ return (ERROR(eclass,ecode));
+ }
- if(!do_lock( fnum, cnum, count, offset, &eclass, &ecode))
- return (ERROR(eclass,ecode));
-
- return(outsize);
+ return(outsize);
}
/****************************************************************************
reply to a unlock
****************************************************************************/
-int reply_unlock(char *inbuf,char *outbuf)
+int reply_unlock(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
{
- int fnum,cnum;
int outsize = set_message(outbuf,0,0,True);
- uint32 count,offset;
+ SMB_BIG_UINT count,offset;
int eclass;
uint32 ecode;
-
- cnum = SVAL(inbuf,smb_tid);
- fnum = GETFNUM(inbuf,smb_vwv0);
+ files_struct *fsp = file_fsp(inbuf,smb_vwv0);
- CHECK_FNUM(fnum,cnum);
- CHECK_ERROR(fnum);
+ CHECK_FSP(fsp,conn);
+ CHECK_ERROR(fsp);
- count = IVAL(inbuf,smb_vwv1);
- offset = IVAL(inbuf,smb_vwv3);
+ count = (SMB_BIG_UINT)IVAL(inbuf,smb_vwv1);
+ offset = (SMB_BIG_UINT)IVAL(inbuf,smb_vwv3);
- if(!do_unlock(fnum, cnum, count, offset, &eclass, &ecode))
+ if(!do_unlock(fsp, conn, count, offset, &eclass, &ecode))
return (ERROR(eclass,ecode));
- DEBUG(3,("%s unlock fd=%d fnum=%d cnum=%d ofs=%d cnt=%d\n",timestring(),Files[fnum].fd,fnum,cnum,offset,count));
+ DEBUG( 3, ( "unlock fd=%d fnum=%d offset=%.0f count=%.0f\n",
+ fsp->fd, fsp->fnum, (double)offset, (double)count ) );
return(outsize);
}
@@ -2051,21 +2873,24 @@ int reply_unlock(char *inbuf,char *outbuf)
/****************************************************************************
reply to a tdis
****************************************************************************/
-int reply_tdis(char *inbuf,char *outbuf)
+int reply_tdis(connection_struct *conn,
+ char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
{
- int cnum, uid;
- int outsize = set_message(outbuf,0,0,True);
-
- cnum = SVAL(inbuf,smb_tid);
- uid = SVAL(inbuf,smb_uid);
+ int outsize = set_message(outbuf,0,0,True);
+ uint16 vuid;
- Connections[cnum].used = False;
+ vuid = SVAL(inbuf,smb_uid);
- close_cnum(cnum,uid);
-
- DEBUG(3,("%s tdis cnum=%d\n",timestring(),cnum));
+ if (!conn) {
+ DEBUG(4,("Invalid connection in tdis\n"));
+ return(ERROR(ERRSRV,ERRinvnid));
+ }
+
+ conn->used = False;
- return outsize;
+ close_cnum(conn,vuid);
+
+ return outsize;
}
@@ -2073,315 +2898,428 @@ int reply_tdis(char *inbuf,char *outbuf)
/****************************************************************************
reply to a echo
****************************************************************************/
-int reply_echo(char *inbuf,char *outbuf)
+int reply_echo(connection_struct *conn,
+ char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
{
- int cnum;
- int smb_reverb = SVAL(inbuf,smb_vwv0);
- int seq_num;
- int data_len = smb_buflen(inbuf);
- int outsize = set_message(outbuf,1,data_len,True);
+ int smb_reverb = SVAL(inbuf,smb_vwv0);
+ int seq_num;
+ unsigned int data_len = smb_buflen(inbuf);
+ int outsize = set_message(outbuf,1,data_len,True);
- cnum = SVAL(inbuf,smb_tid);
+ data_len = MIN(data_len, (sizeof(inbuf)-(smb_buf(inbuf)-inbuf)));
- if (cnum != 0xFFFF && !OPEN_CNUM(cnum))
- {
- DEBUG(4,("Invalid cnum in echo (%d)\n",cnum));
- return(ERROR(ERRSRV,ERRinvnid));
- }
+ /* copy any incoming data back out */
+ if (data_len > 0)
+ memcpy(smb_buf(outbuf),smb_buf(inbuf),data_len);
- /* copy any incoming data back out */
- if (data_len > 0)
- memcpy(smb_buf(outbuf),smb_buf(inbuf),data_len);
+ if (smb_reverb > 100) {
+ DEBUG(0,("large reverb (%d)?? Setting to 100\n",smb_reverb));
+ smb_reverb = 100;
+ }
- if (smb_reverb > 100)
- {
- DEBUG(0,("large reverb (%d)?? Setting to 100\n",smb_reverb));
- smb_reverb = 100;
- }
+ for (seq_num =1 ; seq_num <= smb_reverb ; seq_num++) {
+ SSVAL(outbuf,smb_vwv0,seq_num);
- for (seq_num =1 ; seq_num <= smb_reverb ; seq_num++)
- {
- SSVAL(outbuf,smb_vwv0,seq_num);
+ smb_setlen(outbuf,outsize - 4);
- smb_setlen(outbuf,outsize - 4);
+ send_smb(smbd_server_fd(),outbuf);
+ }
- send_smb(Client,outbuf);
- }
+ DEBUG(3,("echo %d times\n", smb_reverb));
- DEBUG(3,("%s echo %d times cnum=%d\n",timestring(),smb_reverb,cnum));
+ smb_echo_count++;
- return -1;
+ return -1;
}
/****************************************************************************
reply to a printopen
****************************************************************************/
-int reply_printopen(char *inbuf,char *outbuf)
+int reply_printopen(connection_struct *conn,
+ char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
{
- pstring fname;
- pstring fname2;
- int cnum;
- int fnum = -1;
- int outsize = 0;
-
- *fname = *fname2 = 0;
-
- cnum = SVAL(inbuf,smb_tid);
-
- if (!CAN_PRINT(cnum))
- return(ERROR(ERRDOS,ERRnoaccess));
-
- {
- pstring s;
- char *p;
- StrnCpy(s,smb_buf(inbuf)+1,sizeof(pstring)-1);
- p = s;
- while (*p)
- {
- if (!(isalnum(*p) || strchr("._-",*p)))
- *p = 'X';
- p++;
- }
-
- if (strlen(s) > 10) s[10] = 0;
-
- sprintf(fname,"%s.XXXXXX",s);
- }
-
- fnum = find_free_file();
- if (fnum < 0)
- return(ERROR(ERRSRV,ERRnofids));
-
- strcpy(fname2,(char *)mktemp(fname));
-
- if (!check_name(fname2,cnum))
- return(ERROR(ERRDOS,ERRnoaccess));
+ int outsize = 0;
+ files_struct *fsp;
+
+ if (!CAN_PRINT(conn))
+ return(ERROR(ERRDOS,ERRnoaccess));
- open_file(fnum,cnum,fname2,O_WRONLY | O_CREAT | O_TRUNC,
- unix_mode(cnum,0));
+ /* Open for exclusive use, write only. */
+ fsp = print_fsp_open(conn,"dos.prn");
- if (!Files[fnum].open)
- return(UNIXERROR(ERRDOS,ERRnoaccess));
+ if (!fsp) {
+ return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
- /* force it to be a print file */
- Files[fnum].print_file = True;
-
- outsize = set_message(outbuf,1,0,True);
- SSVAL(outbuf,smb_vwv0,fnum);
-
- DEBUG(3,("%s openprint %s fd=%d fnum=%d cnum=%d\n",timestring(),fname2,Files[fnum].fd,fnum,cnum));
+ outsize = set_message(outbuf,1,0,True);
+ SSVAL(outbuf,smb_vwv0,fsp->fnum);
- return(outsize);
+ DEBUG(3,("openprint fd=%d fnum=%d\n",
+ fsp->fd, fsp->fnum));
+
+ return(outsize);
}
/****************************************************************************
reply to a printclose
****************************************************************************/
-int reply_printclose(char *inbuf,char *outbuf)
+int reply_printclose(connection_struct *conn,
+ char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
{
- int fnum,cnum;
- int outsize = set_message(outbuf,0,0,True);
-
- cnum = SVAL(inbuf,smb_tid);
- fnum = GETFNUM(inbuf,smb_vwv0);
+ int outsize = set_message(outbuf,0,0,True);
+ files_struct *fsp = file_fsp(inbuf,smb_vwv0);
+ int close_err = 0;
- CHECK_FNUM(fnum,cnum);
- CHECK_ERROR(fnum);
+ CHECK_FSP(fsp,conn);
+ CHECK_ERROR(fsp);
- if (!CAN_PRINT(cnum))
- return(ERROR(ERRDOS,ERRnoaccess));
-
- close_file(fnum);
+ if (!CAN_PRINT(conn))
+ return(ERROR(ERRDOS,ERRnoaccess));
- DEBUG(3,("%s printclose fd=%d fnum=%d cnum=%d\n",timestring(),Files[fnum].fd,fnum,cnum));
+ DEBUG(3,("printclose fd=%d fnum=%d\n",
+ fsp->fd,fsp->fnum));
- return(outsize);
+ close_err = close_file(fsp,True);
+
+ if(close_err != 0) {
+ errno = close_err;
+ return(UNIXERROR(ERRHRD,ERRgeneral));
+ }
+
+ return(outsize);
}
/****************************************************************************
reply to a printqueue
****************************************************************************/
-int reply_printqueue(char *inbuf,char *outbuf)
+int reply_printqueue(connection_struct *conn,
+ char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
{
- int cnum, uid;
- int outsize = set_message(outbuf,2,3,True);
- int max_count = SVAL(inbuf,smb_vwv0);
- int start_index = SVAL(inbuf,smb_vwv1);
-
- cnum = SVAL(inbuf,smb_tid);
- uid = SVAL(inbuf,smb_uid);
-
-/* allow checking the queue for anyone */
-#if 0
- if (!CAN_PRINT(cnum))
- return(ERROR(ERRDOS,ERRnoaccess));
-#endif
-
- SSVAL(outbuf,smb_vwv0,0);
- SSVAL(outbuf,smb_vwv1,0);
- CVAL(smb_buf(outbuf),0) = 1;
- SSVAL(smb_buf(outbuf),1,0);
+ int outsize = set_message(outbuf,2,3,True);
+ int max_count = SVAL(inbuf,smb_vwv0);
+ int start_index = SVAL(inbuf,smb_vwv1);
+
+ /* we used to allow the client to get the cnum wrong, but that
+ is really quite gross and only worked when there was only
+ one printer - I think we should now only accept it if they
+ get it right (tridge) */
+ if (!CAN_PRINT(conn))
+ return(ERROR(ERRDOS,ERRnoaccess));
+
+ SSVAL(outbuf,smb_vwv0,0);
+ SSVAL(outbuf,smb_vwv1,0);
+ CVAL(smb_buf(outbuf),0) = 1;
+ SSVAL(smb_buf(outbuf),1,0);
- DEBUG(3,("%s printqueue cnum=%d start_index=%d max_count=%d\n",
- timestring(),cnum,start_index,max_count));
-
- if (!OPEN_CNUM(cnum) || !Connections[cnum].printer)
- {
- int i;
- cnum = -1;
-
- for (i=0;i<MAX_CONNECTIONS;i++)
- if (CAN_PRINT(i) && Connections[i].printer)
- cnum = i;
+ DEBUG(3,("printqueue start_index=%d max_count=%d\n",
+ start_index, max_count));
- if (cnum == -1)
- for (i=0;i<MAX_CONNECTIONS;i++)
- if (OPEN_CNUM(i))
- cnum = i;
-
- if (!OPEN_CNUM(cnum))
- return(ERROR(ERRSRV,ERRinvnid));
-
- DEBUG(5,("connection not open or not a printer, using cnum %d\n",cnum));
- }
-
- if (!become_user(cnum,uid))
- return(ERROR(ERRSRV,ERRinvnid));
-
- {
- print_queue_struct *queue = NULL;
- char *p = smb_buf(outbuf) + 3;
- int count = get_printqueue(SNUM(cnum),cnum,&queue,NULL);
- int num_to_get = ABS(max_count);
- int first = (max_count>0?start_index:start_index+max_count+1);
- int i;
-
- if (first >= count)
- num_to_get = 0;
- else
- num_to_get = MIN(num_to_get,count-first);
+ {
+ print_queue_struct *queue = NULL;
+ char *p = smb_buf(outbuf) + 3;
+ int count = print_queue_status(SNUM(conn), &queue,NULL);
+ int num_to_get = ABS(max_count);
+ int first = (max_count>0?start_index:start_index+max_count+1);
+ int i;
+
+ if (first >= count)
+ num_to_get = 0;
+ else
+ num_to_get = MIN(num_to_get,count-first);
- for (i=first;i<first+num_to_get;i++)
- {
- put_dos_date2(p,0,queue[i].time);
- CVAL(p,4) = (queue[i].status==LPQ_PRINTING?2:3);
- SSVAL(p,5,queue[i].job);
- SIVAL(p,7,queue[i].size);
- CVAL(p,11) = 0;
- StrnCpy(p+12,queue[i].user,16);
- p += 28;
- }
+ for (i=first;i<first+num_to_get;i++) {
+ put_dos_date2(p,0,queue[i].time);
+ CVAL(p,4) = (queue[i].status==LPQ_PRINTING?2:3);
+ SSVAL(p,5, queue[i].job);
+ SIVAL(p,7,queue[i].size);
+ CVAL(p,11) = 0;
+ StrnCpy(p+12,queue[i].user,16);
+ p += 28;
+ }
- if (count > 0)
- {
- outsize = set_message(outbuf,2,28*count+3,False);
- SSVAL(outbuf,smb_vwv0,count);
- SSVAL(outbuf,smb_vwv1,(max_count>0?first+count:first-1));
- CVAL(smb_buf(outbuf),0) = 1;
- SSVAL(smb_buf(outbuf),1,28*count);
- }
+ if (count > 0) {
+ outsize = set_message(outbuf,2,28*count+3,False);
+ SSVAL(outbuf,smb_vwv0,count);
+ SSVAL(outbuf,smb_vwv1,(max_count>0?first+count:first-1));
+ CVAL(smb_buf(outbuf),0) = 1;
+ SSVAL(smb_buf(outbuf),1,28*count);
+ }
- if (queue) free(queue);
+ if (queue) free(queue);
- DEBUG(3,("%d entries returned in queue\n",count));
- }
+ DEBUG(3,("%d entries returned in queue\n",count));
+ }
- return(outsize);
+ return(outsize);
}
/****************************************************************************
reply to a printwrite
****************************************************************************/
-int reply_printwrite(char *inbuf,char *outbuf)
+int reply_printwrite(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
{
- int cnum,numtowrite,fnum;
+ int numtowrite;
int outsize = set_message(outbuf,0,0,True);
char *data;
+ files_struct *fsp = file_fsp(inbuf,smb_vwv0);
- cnum = SVAL(inbuf,smb_tid);
-
- if (!CAN_PRINT(cnum))
+ if (!CAN_PRINT(conn))
return(ERROR(ERRDOS,ERRnoaccess));
- fnum = GETFNUM(inbuf,smb_vwv0);
-
- CHECK_FNUM(fnum,cnum);
- CHECK_WRITE(fnum);
- CHECK_ERROR(fnum);
+ CHECK_FSP(fsp,conn);
+ CHECK_WRITE(fsp);
+ CHECK_ERROR(fsp);
numtowrite = SVAL(smb_buf(inbuf),1);
data = smb_buf(inbuf) + 3;
- if (write_file(fnum,data,numtowrite) != numtowrite)
+ if (write_file(fsp,data,-1,numtowrite) != numtowrite)
return(UNIXERROR(ERRDOS,ERRnoaccess));
- DEBUG(3,("%s printwrite fnum=%d cnum=%d num=%d\n",timestring(),fnum,cnum,numtowrite));
+ DEBUG( 3, ( "printwrite fnum=%d num=%d\n", fsp->fnum, numtowrite ) );
return(outsize);
}
/****************************************************************************
- reply to a mkdir
+ The guts of the mkdir command, split out so it may be called by the NT SMB
+ code.
****************************************************************************/
-int reply_mkdir(char *inbuf,char *outbuf)
+int mkdir_internal(connection_struct *conn, char *inbuf, char *outbuf, pstring directory)
{
- pstring directory;
- int cnum;
- int outsize,ret= -1;
+ BOOL bad_path = False;
+ int ret= -1;
- strcpy(directory,smb_buf(inbuf) + 1);
- cnum = SVAL(inbuf,smb_tid);
- unix_convert(directory,cnum);
+ unix_convert(directory,conn,0,&bad_path,NULL);
- if (check_name(directory,cnum))
- ret = sys_mkdir(directory,unix_mode(cnum,aDIR));
+ if (check_name(directory, conn))
+ ret = conn->vfs_ops.mkdir(dos_to_unix(directory,False),
+ unix_mode(conn,aDIR,directory));
if (ret < 0)
+ {
+ if((errno == ENOENT) && bad_path)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
return(UNIXERROR(ERRDOS,ERRnoaccess));
-
- outsize = set_message(outbuf,0,0,True);
-
- DEBUG(3,("%s mkdir %s cnum=%d ret=%d\n",timestring(),directory,cnum,ret));
-
+ }
+
+ return ret;
+}
+
+/****************************************************************************
+ reply to a mkdir
+****************************************************************************/
+int reply_mkdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
+{
+ pstring directory;
+ int outsize;
+
+ pstrcpy(directory,smb_buf(inbuf) + 1);
+
+ outsize=mkdir_internal(conn, inbuf, outbuf, directory);
+ if(outsize == 0)
+ outsize = set_message(outbuf,0,0,True);
+
+ DEBUG( 3, ( "mkdir %s ret=%d\n", directory, outsize ) );
+
return(outsize);
}
+/****************************************************************************
+Static function used by reply_rmdir to delete an entire directory
+tree recursively.
+****************************************************************************/
+
+static BOOL recursive_rmdir(connection_struct *conn, char *directory)
+{
+ char *dname = NULL;
+ BOOL ret = False;
+ void *dirptr = OpenDir(NULL, directory, False);
+
+ if(dirptr == NULL)
+ return True;
+
+ while((dname = ReadDirName(dirptr)))
+ {
+ pstring fullname;
+ SMB_STRUCT_STAT st;
+
+ if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0))
+ continue;
+
+ /* Construct the full name. */
+ if(strlen(directory) + strlen(dname) + 1 >= sizeof(fullname))
+ {
+ errno = ENOMEM;
+ ret = True;
+ break;
+ }
+ pstrcpy(fullname, directory);
+ pstrcat(fullname, "/");
+ pstrcat(fullname, dname);
+
+ if(conn->vfs_ops.lstat(dos_to_unix(fullname,False), &st) != 0)
+ {
+ ret = True;
+ break;
+ }
+
+ if(st.st_mode & S_IFDIR)
+ {
+ if(recursive_rmdir(conn, fullname)!=0)
+ {
+ ret = True;
+ break;
+ }
+ if(conn->vfs_ops.rmdir(dos_to_unix(fullname,False)) != 0)
+ {
+ ret = True;
+ break;
+ }
+ }
+ else if(conn->vfs_ops.unlink(dos_to_unix(fullname,False)) != 0)
+ {
+ ret = True;
+ break;
+ }
+ }
+ CloseDir(dirptr);
+ return ret;
+}
+
+/****************************************************************************
+ The internals of the rmdir code - called elsewhere.
+****************************************************************************/
+
+BOOL rmdir_internals(connection_struct *conn, char *directory)
+{
+ BOOL ok;
+
+ ok = (conn->vfs_ops.rmdir(dos_to_unix(directory, False)) == 0);
+ if(!ok && ((errno == ENOTEMPTY)||(errno == EEXIST)) && lp_veto_files(SNUM(conn)))
+ {
+ /*
+ * Check to see if the only thing in this directory are
+ * vetoed files/directories. If so then delete them and
+ * retry. If we fail to delete any of them (and we *don't*
+ * do a recursive delete) then fail the rmdir.
+ */
+ BOOL all_veto_files = True;
+ char *dname;
+ void *dirptr = OpenDir(conn, directory, False);
+
+ if(dirptr != NULL)
+ {
+ int dirpos = TellDir(dirptr);
+ while ((dname = ReadDirName(dirptr)))
+ {
+ if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0))
+ continue;
+ if(!IS_VETO_PATH(conn, dname))
+ {
+ all_veto_files = False;
+ break;
+ }
+ }
+ if(all_veto_files)
+ {
+ SeekDir(dirptr,dirpos);
+ while ((dname = ReadDirName(dirptr)))
+ {
+ pstring fullname;
+ SMB_STRUCT_STAT st;
+
+ if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0))
+ continue;
+
+ /* Construct the full name. */
+ if(strlen(directory) + strlen(dname) + 1 >= sizeof(fullname))
+ {
+ errno = ENOMEM;
+ break;
+ }
+ pstrcpy(fullname, directory);
+ pstrcat(fullname, "/");
+ pstrcat(fullname, dname);
+
+ if(conn->vfs_ops.lstat(dos_to_unix(fullname, False), &st) != 0)
+ break;
+ if(st.st_mode & S_IFDIR)
+ {
+ if(lp_recursive_veto_delete(SNUM(conn)))
+ {
+ if(recursive_rmdir(conn, fullname) != 0)
+ break;
+ }
+ if(conn->vfs_ops.rmdir(dos_to_unix(fullname, False)) != 0)
+ break;
+ }
+ else if(conn->vfs_ops.unlink(dos_to_unix(fullname, False)) != 0)
+ break;
+ }
+ CloseDir(dirptr);
+ /* Retry the rmdir */
+ ok = (conn->vfs_ops.rmdir(dos_to_unix(directory, False)) == 0);
+ }
+ else
+ CloseDir(dirptr);
+ }
+ else
+ errno = ENOTEMPTY;
+ }
+
+ if (!ok)
+ DEBUG(3,("rmdir_internals: couldn't remove directory %s : %s\n",
+ directory,strerror(errno)));
+
+ return ok;
+}
/****************************************************************************
- reply to a rmdir
+ Reply to a rmdir.
****************************************************************************/
-int reply_rmdir(char *inbuf,char *outbuf)
+
+int reply_rmdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
{
pstring directory;
- int cnum;
int outsize = 0;
BOOL ok = False;
+ BOOL bad_path = False;
+
+ pstrcpy(directory,smb_buf(inbuf) + 1);
+
+ RESOLVE_DFSPATH(directory, conn, inbuf, outbuf)
+
+ unix_convert(directory,conn, NULL,&bad_path,NULL);
- cnum = SVAL(inbuf,smb_tid);
- strcpy(directory,smb_buf(inbuf) + 1);
- unix_convert(directory,cnum);
+ if (check_name(directory,conn))
+ {
+ dptr_closepath(directory,SVAL(inbuf,smb_pid));
+ ok = rmdir_internals(conn, directory);
+ }
- if (check_name(directory,cnum))
+ if (!ok)
+ {
+ if((errno == ENOENT) && bad_path)
{
- dptr_closepath(directory,SVAL(inbuf,smb_pid));
- ok = (sys_rmdir(directory) == 0);
- if (!ok)
- DEBUG(3,("couldn't remove directory %s : %s\n",
- directory,strerror(errno)));
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
}
-
- if (!ok)
return(UNIXERROR(ERRDOS,ERRbadpath));
-
+ }
+
outsize = set_message(outbuf,0,0,True);
- DEBUG(3,("%s rmdir %s\n",timestring(),directory));
+ DEBUG( 3, ( "rmdir %s\n", directory ) );
return(outsize);
}
@@ -2401,21 +3339,21 @@ static BOOL resolve_wildcards(char *name1,char *name2)
if (!name1 || !name2) return(False);
- strcpy(root1,name1);
- strcpy(root2,name2);
+ fstrcpy(root1,name1);
+ fstrcpy(root2,name2);
p = strrchr(root1,'.');
if (p) {
*p = 0;
- strcpy(ext1,p+1);
+ fstrcpy(ext1,p+1);
} else {
- strcpy(ext1,"");
+ fstrcpy(ext1,"");
}
p = strrchr(root2,'.');
if (p) {
*p = 0;
- strcpy(ext2,p+1);
+ fstrcpy(ext2,p+1);
} else {
- strcpy(ext2,"");
+ fstrcpy(ext2,"");
}
p = root1;
@@ -2442,10 +3380,10 @@ static BOOL resolve_wildcards(char *name1,char *name2)
if (*p) p++;
}
- strcpy(name2,root2);
+ pstrcpy(name2,root2);
if (ext2[0]) {
- strcat(name2,".");
- strcat(name2,ext2);
+ pstrcat(name2,".");
+ pstrcat(name2,ext2);
}
return(True);
@@ -2454,121 +3392,255 @@ static BOOL resolve_wildcards(char *name1,char *name2)
/*******************************************************************
check if a user is allowed to rename a file
********************************************************************/
-static BOOL can_rename(char *fname,int cnum)
+static BOOL can_rename(char *fname,connection_struct *conn)
{
- struct stat sbuf;
+ SMB_STRUCT_STAT sbuf;
- if (!CAN_WRITE(cnum)) return(False);
+ if (!CAN_WRITE(conn)) return(False);
- if (sys_lstat(fname,&sbuf) != 0) return(False);
- if (!check_file_sharing(cnum,fname)) return(False);
+ if (conn->vfs_ops.lstat(dos_to_unix(fname,False),&sbuf) != 0) return(False);
+ if (!check_file_sharing(conn,fname,True)) return(False);
return(True);
}
/****************************************************************************
- reply to a mv
+ The guts of the rename command, split out so it may be called by the NT SMB
+ code.
****************************************************************************/
-int reply_mv(char *inbuf,char *outbuf)
+int rename_internals(connection_struct *conn,
+ char *inbuf, char *outbuf, char *name,
+ char *newname, BOOL replace_if_exists)
{
- int outsize = 0;
- pstring name;
- int cnum;
- pstring directory;
- pstring mask,newname;
- char *p;
- int count=0;
- int error = ERRnoaccess;
- BOOL has_wild;
- BOOL exists=False;
-
- *directory = *mask = 0;
-
- cnum = SVAL(inbuf,smb_tid);
-
- strcpy(name,smb_buf(inbuf) + 1);
- strcpy(newname,smb_buf(inbuf) + 3 + strlen(name));
-
- DEBUG(3,("reply_mv : %s -> %s\n",name,newname));
-
- unix_convert(name,cnum);
- unix_convert(newname,cnum);
-
- p = strrchr(name,'/');
- if (!p) {
- strcpy(directory,"./");
- strcpy(mask,name);
- } else {
- *p = 0;
- strcpy(directory,name);
- strcpy(mask,p+1);
- }
+ pstring directory;
+ pstring mask;
+ pstring newname_last_component;
+ char *p;
+ BOOL has_wild;
+ BOOL bad_path1 = False;
+ BOOL bad_path2 = False;
+ int count=0;
+ int error = ERRnoaccess;
+ BOOL exists=False;
+ BOOL rc = True;
+ pstring zdirectory;
+
+ *directory = *mask = 0;
+
+ rc = unix_convert(name,conn,0,&bad_path1,NULL);
+ unix_convert(newname,conn,newname_last_component,&bad_path2,NULL);
+
+ /*
+ * Split the old name into directory and last component
+ * strings. Note that unix_convert may have stripped off a
+ * leading ./ from both name and newname if the rename is
+ * at the root of the share. We need to make sure either both
+ * name and newname contain a / character or neither of them do
+ * as this is checked in resolve_wildcards().
+ */
+
+ p = strrchr(name,'/');
+ if (!p) {
+ pstrcpy(directory,".");
+ pstrcpy(mask,name);
+ } else {
+ *p = 0;
+ pstrcpy(directory,name);
+ pstrcpy(mask,p+1);
+ *p = '/'; /* Replace needed for exceptional test below. */
+ }
- if (is_mangled(mask))
- check_mangled_stack(mask);
+ /*
+ * We should only check the mangled cache
+ * here if unix_convert failed. This means
+ * that the path in 'mask' doesn't exist
+ * on the file system and so we need to look
+ * for a possible mangle. This patch from
+ * Tine Smukavec <valentin.smukavec@hermes.si>.
+ */
+
+ if (!rc && is_mangled(mask))
+ check_mangled_cache( mask );
+
+ has_wild = ms_has_wild(mask);
+
+ if (!has_wild) {
+ /*
+ * No wildcards - just process the one file.
+ */
+ BOOL is_short_name = is_8_3(name, True);
+
+ /* Add a terminating '/' to the directory name. */
+ pstrcat(directory,"/");
+ pstrcat(directory,mask);
+
+ /* Ensure newname contains a '/' also */
+ if(strrchr(newname,'/') == 0) {
+ pstring tmpstr;
+
+ pstrcpy(tmpstr, "./");
+ pstrcat(tmpstr, newname);
+ pstrcpy(newname, tmpstr);
+ }
+
+ DEBUG(3,("rename_internals: case_sensitive = %d, case_preserve = %d, short case preserve = %d, directory = %s, newname = %s, newname_last_component = %s, is_8_3 = %d\n",
+ case_sensitive, case_preserve, short_case_preserve, directory,
+ newname, newname_last_component, is_short_name));
+
+ /*
+ * Check for special case with case preserving and not
+ * case sensitive, if directory and newname are identical,
+ * and the old last component differs from the original
+ * last component only by case, then we should allow
+ * the rename (user is trying to change the case of the
+ * filename).
+ */
+ if((case_sensitive == False) &&
+ (((case_preserve == True) &&
+ (is_short_name == False)) ||
+ ((short_case_preserve == True) &&
+ (is_short_name == True))) &&
+ strcsequal(directory, newname)) {
+ pstring newname_modified_last_component;
+
+ /*
+ * Get the last component of the modified name.
+ * Note that we guarantee that newname contains a '/'
+ * character above.
+ */
+ p = strrchr(newname,'/');
+ pstrcpy(newname_modified_last_component,p+1);
+
+ if(strcsequal(newname_modified_last_component,
+ newname_last_component) == False) {
+ /*
+ * Replace the modified last component with
+ * the original.
+ */
+ pstrcpy(p+1, newname_last_component);
+ }
+ }
+
+ pstrcpy(zdirectory, dos_to_unix(directory, False));
+ if(replace_if_exists) {
+ /*
+ * NT SMB specific flag - rename can overwrite
+ * file with the same name so don't check for
+ * vfs_file_exist().
+ */
+ if(resolve_wildcards(directory,newname) &&
+ can_rename(directory,conn) &&
+ !conn->vfs_ops.rename(zdirectory,
+ dos_to_unix(newname,False)))
+ count++;
+ } else {
+ if (resolve_wildcards(directory,newname) &&
+ can_rename(directory,conn) &&
+ !vfs_file_exist(conn,newname,NULL) &&
+ !conn->vfs_ops.rename(zdirectory,
+ dos_to_unix(newname,False)))
+ count++;
+ }
- has_wild = strchr(mask,'*') || strchr(mask,'?');
+ DEBUG(3,("rename_internals: %s doing rename on %s -> %s\n",(count != 0) ? "succeeded" : "failed",
+ directory,newname));
+
+ if (!count) exists = vfs_file_exist(conn,directory,NULL);
+ if (!count && exists && vfs_file_exist(conn,newname,NULL)) {
+ exists = True;
+ error = ERRrename;
+ }
+ } else {
+ /*
+ * Wildcards - process each file that matches.
+ */
+ void *dirptr = NULL;
+ char *dname;
+ pstring destname;
+
+ if (check_name(directory,conn))
+ dirptr = OpenDir(conn, directory, True);
+
+ if (dirptr) {
+ error = ERRbadfile;
+
+ if (strequal(mask,"????????.???"))
+ pstrcpy(mask,"*");
+
+ while ((dname = ReadDirName(dirptr))) {
+ pstring fname;
+
+ pstrcpy(fname,dname);
+
+ if(!mask_match(fname, mask, case_sensitive))
+ continue;
+
+ error = ERRnoaccess;
+ slprintf(fname,sizeof(fname)-1,"%s/%s",directory,dname);
+ if (!can_rename(fname,conn)) {
+ DEBUG(6,("rename %s refused\n", fname));
+ continue;
+ }
+ pstrcpy(destname,newname);
+
+ if (!resolve_wildcards(fname,destname)) {
+ DEBUG(6,("resolve_wildcards %s %s failed\n",
+ fname, destname));
+ continue;
+ }
+
+ if (!replace_if_exists &&
+ vfs_file_exist(conn,destname, NULL)) {
+ DEBUG(6,("file_exist %s\n", destname));
+ error = 183;
+ continue;
+ }
+
+ if (!conn->vfs_ops.rename(dos_to_unix(fname,False),
+ dos_to_unix(destname,False)))
+ count++;
+ DEBUG(3,("rename_internals: doing rename on %s -> %s\n",fname,destname));
+ }
+ CloseDir(dirptr);
+ }
+ }
+
+ if (count == 0) {
+ if (exists)
+ return(ERROR(ERRDOS,error));
+ else {
+ if((errno == ENOENT) && (bad_path1 || bad_path2)) {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
+ return(UNIXERROR(ERRDOS,error));
+ }
+ }
+
+ return 0;
+}
- if (!has_wild) {
- strcat(directory,"/");
- strcat(directory,mask);
- if (resolve_wildcards(directory,newname) &&
- can_rename(directory,cnum) &&
- !file_exist(newname,NULL) &&
- !sys_rename(directory,newname)) count++;
- if (!count) exists = file_exist(directory,NULL);
- if (!count && exists && file_exist(newname,NULL)) {
- exists = True;
- error = 183;
- }
- } else {
- void *dirptr = NULL;
- char *dname;
- pstring destname;
+/****************************************************************************
+ Reply to a mv.
+****************************************************************************/
- if (check_name(directory,cnum))
- dirptr = OpenDir(directory);
+int reply_mv(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
+{
+ int outsize = 0;
+ pstring name;
+ pstring newname;
- if (dirptr)
- {
- error = ERRbadfile;
+ pstrcpy(name,smb_buf(inbuf) + 1);
+ pstrcpy(newname,smb_buf(inbuf) + 3 + strlen(name));
- if (strequal(mask,"????????.???"))
- strcpy(mask,"*");
+ RESOLVE_DFSPATH(name, conn, inbuf, outbuf);
+ RESOLVE_DFSPATH(newname, conn, inbuf, outbuf);
- while ((dname = ReadDirName(dirptr)))
- {
- pstring fname;
- strcpy(fname,dname);
-
- if(!mask_match(fname, mask, case_sensitive, False)) continue;
+ DEBUG(3,("reply_mv : %s -> %s\n",name,newname));
- error = ERRnoaccess;
- sprintf(fname,"%s/%s",directory,dname);
- if (!can_rename(fname,cnum)) continue;
- strcpy(destname,newname);
-
- if (!resolve_wildcards(fname,destname)) continue;
-
- if (file_exist(destname,NULL)) {
- error = 183;
- continue;
- }
- if (!sys_rename(fname,destname)) count++;
- DEBUG(3,("reply_mv : doing rename on %s -> %s\n",fname,destname));
- }
- CloseDir(dirptr);
- }
- }
-
- if (count == 0) {
- if (exists)
- return(ERROR(ERRDOS,error));
- else
- return(UNIXERROR(ERRDOS,error));
- }
-
- outsize = set_message(outbuf,0,0,True);
+ outsize = rename_internals(conn, inbuf, outbuf, name, newname, False);
+ if(outsize == 0)
+ outsize = set_message(outbuf,0,0,True);
return(outsize);
}
@@ -2576,62 +3648,75 @@ int reply_mv(char *inbuf,char *outbuf)
/*******************************************************************
copy a file as part of a reply_copy
******************************************************************/
-static BOOL copy_file(char *src,char *dest1,int cnum,int ofun,
- int count,BOOL target_is_directory)
+
+static BOOL copy_file(char *src,char *dest1,connection_struct *conn, int ofun,
+ int count,BOOL target_is_directory, int *err_ret)
{
int Access,action;
- struct stat st;
- int ret=0;
- int fnum1,fnum2;
+ SMB_STRUCT_STAT st;
+ SMB_OFF_T ret=-1;
+ files_struct *fsp1,*fsp2;
pstring dest;
- strcpy(dest,dest1);
+ *err_ret = 0;
+
+ pstrcpy(dest,dest1);
if (target_is_directory) {
char *p = strrchr(src,'/');
if (p)
p++;
else
p = src;
- strcat(dest,"/");
- strcat(dest,p);
+ pstrcat(dest,"/");
+ pstrcat(dest,p);
}
- if (!file_exist(src,&st)) return(False);
+ if (!vfs_file_exist(conn,src,&st))
+ return(False);
- fnum1 = find_free_file();
- if (fnum1<0) return(False);
- open_file_shared(fnum1,cnum,src,(DENY_NONE<<4),
- 1,0,&Access,&action);
+ fsp1 = open_file_shared(conn,src,SET_DENY_MODE(DENY_NONE)|SET_OPEN_MODE(DOS_OPEN_RDONLY),
+ (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),0,0,&Access,&action);
- if (!Files[fnum1].open) return(False);
+ if (!fsp1) {
+ return(False);
+ }
if (!target_is_directory && count)
ofun = 1;
- fnum2 = find_free_file();
- if (fnum2<0) {
- close_file(fnum1);
- return(False);
- }
- open_file_shared(fnum2,cnum,dest,(DENY_NONE<<4)|1,
- ofun,st.st_mode,&Access,&action);
+ fsp2 = open_file_shared(conn,dest,SET_DENY_MODE(DENY_NONE)|SET_OPEN_MODE(DOS_OPEN_WRONLY),
+ ofun,st.st_mode,0,&Access,&action);
- if (!Files[fnum2].open) {
- close_file(fnum1);
+ if (!fsp2) {
+ close_file(fsp1,False);
return(False);
}
if ((ofun&3) == 1) {
- lseek(Files[fnum2].fd,0,SEEK_END);
+ if(conn->vfs_ops.lseek(fsp2->fd,0,SEEK_END) == -1) {
+ DEBUG(0,("copy_file: error - sys_lseek returned error %s\n",
+ strerror(errno) ));
+ /*
+ * Stop the copy from occurring.
+ */
+ ret = -1;
+ st.st_size = 0;
+ }
}
if (st.st_size)
- ret = transfer_file(Files[fnum1].fd,Files[fnum2].fd,st.st_size,NULL,0,0);
-
- close_file(fnum1);
- close_file(fnum2);
-
- return(ret == st.st_size);
+ ret = vfs_transfer_file(-1, fsp1, -1, fsp2, st.st_size, NULL, 0, 0);
+
+ close_file(fsp1,False);
+ /*
+ * As we are opening fsp1 read-only we only expect
+ * an error on close on fsp2 if we are out of space.
+ * Thus we don't look at the error return from the
+ * close of fsp1.
+ */
+ *err_ret = close_file(fsp2,False);
+
+ return(ret == (SMB_OFF_T)st.st_size);
}
@@ -2639,42 +3724,46 @@ static BOOL copy_file(char *src,char *dest1,int cnum,int ofun,
/****************************************************************************
reply to a file copy.
****************************************************************************/
-int reply_copy(char *inbuf,char *outbuf)
+int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
{
int outsize = 0;
pstring name;
- int cnum;
pstring directory;
pstring mask,newname;
char *p;
int count=0;
int error = ERRnoaccess;
+ int err = 0;
BOOL has_wild;
BOOL exists=False;
int tid2 = SVAL(inbuf,smb_vwv0);
int ofun = SVAL(inbuf,smb_vwv1);
int flags = SVAL(inbuf,smb_vwv2);
BOOL target_is_directory=False;
+ BOOL bad_path1 = False;
+ BOOL bad_path2 = False;
+ BOOL rc = True;
*directory = *mask = 0;
- cnum = SVAL(inbuf,smb_tid);
-
- strcpy(name,smb_buf(inbuf));
- strcpy(newname,smb_buf(inbuf) + 1 + strlen(name));
+ pstrcpy(name,smb_buf(inbuf));
+ pstrcpy(newname,smb_buf(inbuf) + 1 + strlen(name));
DEBUG(3,("reply_copy : %s -> %s\n",name,newname));
- if (tid2 != cnum) {
+ if (tid2 != conn->cnum) {
/* can't currently handle inter share copies XXXX */
DEBUG(3,("Rejecting inter-share copy\n"));
return(ERROR(ERRSRV,ERRinvdevice));
}
- unix_convert(name,cnum);
- unix_convert(newname,cnum);
+ RESOLVE_DFSPATH(name, conn, inbuf, outbuf);
+ RESOLVE_DFSPATH(newname, conn, inbuf, outbuf);
- target_is_directory = directory_exist(newname,NULL);
+ rc = unix_convert(name,conn,0,&bad_path1,NULL);
+ unix_convert(newname,conn,0,&bad_path2,NULL);
+
+ target_is_directory = vfs_directory_exist(conn,False,NULL);
if ((flags&1) && target_is_directory) {
return(ERROR(ERRDOS,ERRbadfile));
@@ -2684,7 +3773,7 @@ int reply_copy(char *inbuf,char *outbuf)
return(ERROR(ERRDOS,ERRbadpath));
}
- if ((flags&(1<<5)) && directory_exist(name,NULL)) {
+ if ((flags&(1<<5)) && vfs_directory_exist(conn,name,NULL)) {
/* wants a tree copy! XXXX */
DEBUG(3,("Rejecting tree copy\n"));
return(ERROR(ERRSRV,ERRerror));
@@ -2692,65 +3781,90 @@ int reply_copy(char *inbuf,char *outbuf)
p = strrchr(name,'/');
if (!p) {
- strcpy(directory,"./");
- strcpy(mask,name);
+ pstrcpy(directory,"./");
+ pstrcpy(mask,name);
} else {
*p = 0;
- strcpy(directory,name);
- strcpy(mask,p+1);
+ pstrcpy(directory,name);
+ pstrcpy(mask,p+1);
}
- if (is_mangled(mask))
- check_mangled_stack(mask);
+ /*
+ * We should only check the mangled cache
+ * here if unix_convert failed. This means
+ * that the path in 'mask' doesn't exist
+ * on the file system and so we need to look
+ * for a possible mangle. This patch from
+ * Tine Smukavec <valentin.smukavec@hermes.si>.
+ */
+
+ if (!rc && is_mangled(mask))
+ check_mangled_cache( mask );
- has_wild = strchr(mask,'*') || strchr(mask,'?');
+ has_wild = ms_has_wild(mask);
if (!has_wild) {
- strcat(directory,"/");
- strcat(directory,mask);
+ pstrcat(directory,"/");
+ pstrcat(directory,mask);
if (resolve_wildcards(directory,newname) &&
- copy_file(directory,newname,cnum,ofun,
- count,target_is_directory)) count++;
- if (!count) exists = file_exist(directory,NULL);
+ copy_file(directory,newname,conn,ofun,
+ count,target_is_directory,&err)) count++;
+ if(!count && err) {
+ errno = err;
+ return(UNIXERROR(ERRHRD,ERRgeneral));
+ }
+ if (!count) exists = vfs_file_exist(conn,directory,NULL);
} else {
void *dirptr = NULL;
char *dname;
pstring destname;
- if (check_name(directory,cnum))
- dirptr = OpenDir(directory);
+ if (check_name(directory,conn))
+ dirptr = OpenDir(conn, directory, True);
- if (dirptr)
- {
+ if (dirptr) {
error = ERRbadfile;
if (strequal(mask,"????????.???"))
- strcpy(mask,"*");
+ pstrcpy(mask,"*");
- while ((dname = ReadDirName(dirptr)))
- {
+ while ((dname = ReadDirName(dirptr))) {
pstring fname;
- strcpy(fname,dname);
+ pstrcpy(fname,dname);
- if(!mask_match(fname, mask, case_sensitive, False)) continue;
+ if(!mask_match(fname, mask, case_sensitive))
+ continue;
error = ERRnoaccess;
- sprintf(fname,"%s/%s",directory,dname);
- strcpy(destname,newname);
+ slprintf(fname,sizeof(fname)-1, "%s/%s",directory,dname);
+ pstrcpy(destname,newname);
if (resolve_wildcards(fname,destname) &&
- copy_file(directory,newname,cnum,ofun,
- count,target_is_directory)) count++;
+ copy_file(fname,destname,conn,ofun,
+ count,target_is_directory,&err)) count++;
DEBUG(3,("reply_copy : doing copy on %s -> %s\n",fname,destname));
}
CloseDir(dirptr);
- }
+ }
}
if (count == 0) {
+ if(err) {
+ /* Error on close... */
+ errno = err;
+ return(UNIXERROR(ERRHRD,ERRgeneral));
+ }
+
if (exists)
return(ERROR(ERRDOS,error));
else
+ {
+ if((errno == ENOENT) && (bad_path1 || bad_path2))
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
return(UNIXERROR(ERRDOS,error));
+ }
}
outsize = set_message(outbuf,1,0,True);
@@ -2759,139 +3873,301 @@ int reply_copy(char *inbuf,char *outbuf)
return(outsize);
}
-
-
/****************************************************************************
reply to a setdir
****************************************************************************/
-int reply_setdir(char *inbuf,char *outbuf)
+int reply_setdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
{
- int cnum,snum;
+ int snum;
int outsize = 0;
BOOL ok = False;
pstring newdir;
- cnum = SVAL(inbuf,smb_tid);
-
- snum = Connections[cnum].service;
+ snum = SNUM(conn);
if (!CAN_SETDIR(snum))
return(ERROR(ERRDOS,ERRnoaccess));
- strcpy(newdir,smb_buf(inbuf) + 1);
+ pstrcpy(newdir,smb_buf(inbuf) + 1);
strlower(newdir);
- if (strlen(newdir) == 0)
- ok = True;
- else
- {
- ok = directory_exist(newdir,NULL);
- if (ok)
- string_set(&Connections[cnum].connectpath,newdir);
- }
+ if (strlen(newdir) == 0) {
+ ok = True;
+ } else {
+ ok = vfs_directory_exist(conn,newdir,NULL);
+ if (ok) {
+ string_set(&conn->connectpath,newdir);
+ }
+ }
if (!ok)
- return(ERROR(ERRDOS,ERRbadpath));
+ return(ERROR(ERRDOS,ERRbadpath));
outsize = set_message(outbuf,0,0,True);
CVAL(outbuf,smb_reh) = CVAL(inbuf,smb_reh);
- DEBUG(3,("%s setdir %s cnum=%d\n",timestring(),newdir,cnum));
-
+ DEBUG(3,("setdir %s\n", newdir));
+
return(outsize);
}
+/****************************************************************************
+ Get a lock count, dealing with large count requests.
+****************************************************************************/
+
+SMB_BIG_UINT get_lock_count( char *data, int data_offset, BOOL large_file_format)
+{
+ SMB_BIG_UINT count = 0;
+
+ if(!large_file_format) {
+ count = (SMB_BIG_UINT)IVAL(data,SMB_LKLEN_OFFSET(data_offset));
+ } else {
+
+#if defined(HAVE_LONGLONG)
+ count = (((SMB_BIG_UINT) IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset))) << 32) |
+ ((SMB_BIG_UINT) IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)));
+#else /* HAVE_LONGLONG */
+
+ /*
+ * NT4.x seems to be broken in that it sends large file (64 bit)
+ * lockingX calls even if the CAP_LARGE_FILES was *not*
+ * negotiated. For boxes without large unsigned ints truncate the
+ * lock count by dropping the top 32 bits.
+ */
+
+ if(IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset)) != 0) {
+ DEBUG(3,("get_lock_count: truncating lock count (high)0x%x (low)0x%x to just low count.\n",
+ (unsigned int)IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset)),
+ (unsigned int)IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)) ));
+ SIVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset),0);
+ }
+
+ count = (SMB_BIG_UINT)IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset));
+#endif /* HAVE_LONGLONG */
+ }
+
+ return count;
+}
+
+/****************************************************************************
+ Get a lock offset, dealing with large offset requests.
+****************************************************************************/
+
+SMB_BIG_UINT get_lock_offset( char *data, int data_offset, BOOL large_file_format, BOOL *err)
+{
+ SMB_BIG_UINT offset = 0;
+
+ *err = False;
+
+ if(!large_file_format) {
+ offset = (SMB_BIG_UINT)IVAL(data,SMB_LKOFF_OFFSET(data_offset));
+ } else {
+
+#if defined(HAVE_LONGLONG)
+ offset = (((SMB_BIG_UINT) IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset))) << 32) |
+ ((SMB_BIG_UINT) IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset)));
+#else /* HAVE_LONGLONG */
+
+ /*
+ * NT4.x seems to be broken in that it sends large file (64 bit)
+ * lockingX calls even if the CAP_LARGE_FILES was *not*
+ * negotiated. For boxes without large unsigned ints mangle the
+ * lock offset by mapping the top 32 bits onto the lower 32.
+ */
+
+ if(IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset)) != 0) {
+ uint32 low = IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset));
+ uint32 high = IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset));
+ uint32 new_low = 0;
+
+ if((new_low = map_lock_offset(high, low)) == 0) {
+ *err = True;
+ return (SMB_BIG_UINT)-1;
+ }
+
+ DEBUG(3,("get_lock_offset: truncating lock offset (high)0x%x (low)0x%x to offset 0x%x.\n",
+ (unsigned int)high, (unsigned int)low, (unsigned int)new_low ));
+ SIVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset),0);
+ SIVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset),new_low);
+ }
+
+ offset = (SMB_BIG_UINT)IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset));
+#endif /* HAVE_LONGLONG */
+ }
+
+ return offset;
+}
/****************************************************************************
reply to a lockingX request
****************************************************************************/
-int reply_lockingX(char *inbuf,char *outbuf,int length,int bufsize)
+
+int reply_lockingX(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
{
- int smb_com2 = CVAL(inbuf,smb_vwv0);
- int smb_off2 = SVAL(inbuf,smb_vwv1);
- int fnum = GETFNUM(inbuf,smb_vwv2);
- uint16 locktype = SVAL(inbuf,smb_vwv3);
+ files_struct *fsp = file_fsp(inbuf,smb_vwv2);
+ unsigned char locktype = CVAL(inbuf,smb_vwv3);
+#if 0
+ unsigned char oplocklevel = CVAL(inbuf,smb_vwv3+1);
+#endif
uint16 num_ulocks = SVAL(inbuf,smb_vwv6);
uint16 num_locks = SVAL(inbuf,smb_vwv7);
- uint32 count, offset;
-
- int cnum;
+ SMB_BIG_UINT count = 0, offset = 0;
+ int32 lock_timeout = IVAL(inbuf,smb_vwv4);
int i;
char *data;
uint32 ecode=0, dummy2;
- int outsize, eclass=0, dummy1;
-
- cnum = SVAL(inbuf,smb_tid);
+ int eclass=0, dummy1;
+ BOOL large_file_format = (locktype & LOCKING_ANDX_LARGE_FILES);
+ BOOL err;
- CHECK_FNUM(fnum,cnum);
- CHECK_ERROR(fnum);
+ CHECK_FSP(fsp,conn);
+ CHECK_ERROR(fsp);
data = smb_buf(inbuf);
+
+ /* Check if this is an oplock break on a file
+ we have granted an oplock on.
+ */
+ if ((locktype & LOCKING_ANDX_OPLOCK_RELEASE))
+ {
+ DEBUG(5,("reply_lockingX: oplock break reply from client for fnum = %d\n",
+ fsp->fnum));
+
+ /*
+ * Make sure we have granted an exclusive or batch oplock on this file.
+ */
+
+ if(!EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type))
+ {
+ DEBUG(0,("reply_lockingX: Error : oplock break from client for fnum = %d and \
+no oplock granted on this file (%s).\n", fsp->fnum, fsp->fsp_name));
+
+ /* if this is a pure oplock break request then don't send a reply */
+ if (num_locks == 0 && num_ulocks == 0)
+ return -1;
+ else
+ return ERROR(ERRDOS,ERRlock);
+ }
+
+ if (remove_oplock(fsp) == False) {
+ DEBUG(0,("reply_lockingX: error in removing oplock on file %s\n",
+ fsp->fsp_name ));
+ }
+
+ /* if this is a pure oplock break request then don't send a reply */
+ if (num_locks == 0 && num_ulocks == 0)
+ {
+ /* Sanity check - ensure a pure oplock break is not a
+ chained request. */
+ if(CVAL(inbuf,smb_vwv0) != 0xff)
+ DEBUG(0,("reply_lockingX: Error : pure oplock break is a chained %d request !\n",
+ (unsigned int)CVAL(inbuf,smb_vwv0) ));
+ return -1;
+ }
+ }
+
/* Data now points at the beginning of the list
of smb_unlkrng structs */
for(i = 0; i < (int)num_ulocks; i++) {
- count = IVAL(data,SMB_LKLEN_OFFSET(i));
- offset = IVAL(data,SMB_LKOFF_OFFSET(i));
- if(!do_unlock(fnum,cnum,count,offset,&eclass, &ecode))
+ count = get_lock_count( data, i, large_file_format);
+ offset = get_lock_offset( data, i, large_file_format, &err);
+
+ /*
+ * There is no error code marked "stupid client bug".... :-).
+ */
+ if(err)
+ return ERROR(ERRDOS,ERRnoaccess);
+
+ DEBUG(10,("reply_lockingX: unlock start=%.0f, len=%.0f for file %s\n",
+ (double)offset, (double)count, fsp->fsp_name ));
+
+ if(!do_unlock(fsp,conn,count,offset, &eclass, &ecode))
return ERROR(eclass,ecode);
}
+ /* Setup the timeout in seconds. */
+ lock_timeout = ((lock_timeout == -1) ? -1 : lock_timeout/1000);
+
/* Now do any requested locks */
- data += 10*num_ulocks;
+ data += ((large_file_format ? 20 : 10)*num_ulocks);
+
/* Data now points at the beginning of the list
of smb_lkrng structs */
+
for(i = 0; i < (int)num_locks; i++) {
- count = IVAL(data,SMB_LKLEN_OFFSET(i));
- offset = IVAL(data,SMB_LKOFF_OFFSET(i));
- if(!do_lock(fnum,cnum,count,offset, &eclass, &ecode))
+ count = get_lock_count( data, i, large_file_format);
+ offset = get_lock_offset( data, i, large_file_format, &err);
+
+ /*
+ * There is no error code marked "stupid client bug".... :-).
+ */
+ if(err)
+ return ERROR(ERRDOS,ERRnoaccess);
+
+ DEBUG(10,("reply_lockingX: lock start=%.0f, len=%.0f for file %s\n",
+ (double)offset, (double)count, fsp->fsp_name ));
+
+ if(!do_lock(fsp,conn,count,offset, ((locktype & 1) ? READ_LOCK : WRITE_LOCK),
+ &eclass, &ecode)) {
+ if((ecode == ERRlock) && (lock_timeout != 0) && lp_blocking_locks(SNUM(conn))) {
+ /*
+ * A blocking lock was requested. Package up
+ * this smb into a queued request and push it
+ * onto the blocking lock queue.
+ */
+ if(push_blocking_lock_request(inbuf, length, lock_timeout, i))
+ return -1;
+ }
break;
+ }
}
/* If any of the above locks failed, then we must unlock
all of the previous locks (X/Open spec). */
if(i != num_locks && num_locks != 0) {
- for(; i >= 0; i--) {
- count = IVAL(data,SMB_LKLEN_OFFSET(i));
- offset = IVAL(data,SMB_LKOFF_OFFSET(i));
- do_unlock(fnum,cnum,count,offset,&dummy1,&dummy2);
+ /*
+ * Ensure we don't do a remove on the lock that just failed,
+ * as under POSIX rules, if we have a lock already there, we
+ * will delete it (and we shouldn't) .....
+ */
+ for(i--; i >= 0; i--) {
+ count = get_lock_count( data, i, large_file_format);
+ offset = get_lock_offset( data, i, large_file_format, &err);
+
+ /*
+ * There is no error code marked "stupid client bug".... :-).
+ */
+ if(err)
+ return ERROR(ERRDOS,ERRnoaccess);
+
+ do_unlock(fsp,conn,count,offset,&dummy1,&dummy2);
}
return ERROR(eclass,ecode);
}
- outsize = set_message(outbuf,2,0,True);
+ set_message(outbuf,2,0,True);
- CVAL(outbuf,smb_vwv0) = smb_com2;
- SSVAL(outbuf,smb_vwv1,(outsize+chain_size)-4);
-
- DEBUG(3,("%s lockingX fnum=%d cnum=%d type=%d num_locks=%d num_ulocks=%d\n",
- timestring(),fnum,cnum,locktype,num_locks,num_ulocks));
-
- chain_fnum = fnum;
+ DEBUG( 3, ( "lockingX fnum=%d type=%d num_locks=%d num_ulocks=%d\n",
+ fsp->fnum, (unsigned int)locktype, num_locks, num_ulocks ) );
- if (smb_com2 != 0xFF)
- outsize += chain_reply(smb_com2,inbuf,inbuf+smb_off2+4,
- outbuf,outbuf+outsize,
- length,bufsize);
-
- chain_fnum = -1;
-
- return(outsize);
+ return chain_reply(inbuf,outbuf,length,bufsize);
}
/****************************************************************************
reply to a SMBreadbmpx (read block multiplex) request
****************************************************************************/
-int reply_readbmpx(char *inbuf,char *outbuf,int length,int bufsize)
+int reply_readbmpx(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
{
- int cnum,fnum;
- int nread = -1;
- int total_read;
+ ssize_t nread = -1;
+ ssize_t total_read;
char *data;
- int32 startpos;
- int outsize, mincount, maxcount;
+ SMB_OFF_T startpos;
+ int outsize;
+ size_t maxcount;
int max_per_packet;
- int tcount;
+ size_t tcount;
int pad;
+ files_struct *fsp = file_fsp(inbuf,smb_vwv0);
/* this function doesn't seem to work - disable by default */
if (!lp_readbmpx())
@@ -2899,19 +4175,15 @@ int reply_readbmpx(char *inbuf,char *outbuf,int length,int bufsize)
outsize = set_message(outbuf,8,0,True);
- cnum = SVAL(inbuf,smb_tid);
- fnum = GETFNUM(inbuf,smb_vwv0);
-
- CHECK_FNUM(fnum,cnum);
- CHECK_READ(fnum);
- CHECK_ERROR(fnum);
+ CHECK_FSP(fsp,conn);
+ CHECK_READ(fsp);
+ CHECK_ERROR(fsp);
startpos = IVAL(inbuf,smb_vwv1);
maxcount = SVAL(inbuf,smb_vwv3);
- mincount = SVAL(inbuf,smb_vwv4);
data = smb_buf(outbuf);
- pad = ((int)data)%4;
+ pad = ((long)data)%4;
if (pad) pad = 4 - pad;
data += pad;
@@ -2919,19 +4191,19 @@ int reply_readbmpx(char *inbuf,char *outbuf,int length,int bufsize)
tcount = maxcount;
total_read = 0;
- if (is_locked(fnum,cnum,maxcount,startpos))
+ if (is_locked(fsp,conn,(SMB_BIG_UINT)maxcount,(SMB_BIG_UINT)startpos, READ_LOCK))
return(ERROR(ERRDOS,ERRlock));
do
{
- int N = MIN(max_per_packet,tcount-total_read);
+ size_t N = MIN(max_per_packet,tcount-total_read);
- nread = read_file(fnum,data,startpos,N,N,-1,False);
+ nread = read_file(fsp,data,startpos,N);
if (nread <= 0) nread = 0;
- if (nread < N)
- tcount = total_read + nread;
+ if (nread < (ssize_t)N)
+ tcount = total_read + nread;
set_message(outbuf,8,nread,False);
SIVAL(outbuf,smb_vwv0,startpos);
@@ -2939,35 +4211,35 @@ int reply_readbmpx(char *inbuf,char *outbuf,int length,int bufsize)
SSVAL(outbuf,smb_vwv6,nread);
SSVAL(outbuf,smb_vwv7,smb_offset(data,outbuf));
- send_smb(Client,outbuf);
+ send_smb(smbd_server_fd(),outbuf);
total_read += nread;
startpos += nread;
}
- while (total_read < tcount);
+ while (total_read < (ssize_t)tcount);
return(-1);
}
-
/****************************************************************************
reply to a SMBwritebmpx (write block multiplex primary) request
****************************************************************************/
-int reply_writebmpx(char *inbuf,char *outbuf)
+
+int reply_writebmpx(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
{
- int cnum,numtowrite,fnum;
- int nwritten = -1;
+ size_t numtowrite;
+ ssize_t nwritten = -1;
int outsize = 0;
- int32 startpos;
- int tcount, write_through, smb_doff;
+ SMB_OFF_T startpos;
+ size_t tcount;
+ BOOL write_through;
+ int smb_doff;
char *data;
-
- cnum = SVAL(inbuf,smb_tid);
- fnum = GETFNUM(inbuf,smb_vwv0);
+ files_struct *fsp = file_fsp(inbuf,smb_vwv0);
- CHECK_FNUM(fnum,cnum);
- CHECK_WRITE(fnum);
- CHECK_ERROR(fnum);
+ CHECK_FSP(fsp,conn);
+ CHECK_WRITE(fsp);
+ CHECK_ERROR(fsp);
tcount = SVAL(inbuf,smb_vwv1);
startpos = IVAL(inbuf,smb_vwv3);
@@ -2981,41 +4253,40 @@ int reply_writebmpx(char *inbuf,char *outbuf)
not an SMBwritebmpx - set this up now so we don't forget */
CVAL(outbuf,smb_com) = SMBwritec;
- if (is_locked(fnum,cnum,tcount,startpos))
+ if (is_locked(fsp,conn,(SMB_BIG_UINT)tcount,(SMB_BIG_UINT)startpos,WRITE_LOCK))
return(ERROR(ERRDOS,ERRlock));
- seek_file(fnum,startpos);
- nwritten = write_file(fnum,data,numtowrite);
+ nwritten = write_file(fsp,data,startpos,numtowrite);
- if(lp_syncalways(SNUM(cnum)) || write_through)
- sync_file(fnum);
+ if(lp_syncalways(SNUM(conn)) || write_through)
+ sync_file(conn,fsp);
- if(nwritten < numtowrite)
+ if(nwritten < (ssize_t)numtowrite)
return(UNIXERROR(ERRHRD,ERRdiskfull));
/* If the maximum to be written to this file
is greater than what we just wrote then set
up a secondary struct to be attached to this
fd, we will use this to cache error messages etc. */
- if(tcount > nwritten)
+ if((ssize_t)tcount > nwritten)
+ {
+ write_bmpx_struct *wbms;
+ if(fsp->wbmpx_ptr != NULL)
+ wbms = fsp->wbmpx_ptr; /* Use an existing struct */
+ else
+ wbms = (write_bmpx_struct *)malloc(sizeof(write_bmpx_struct));
+ if(!wbms)
{
- write_bmpx_struct *wbms;
- if(Files[fnum].wbmpx_ptr != NULL)
- wbms = Files[fnum].wbmpx_ptr; /* Use an existing struct */
- else
- wbms = (write_bmpx_struct *)malloc(sizeof(write_bmpx_struct));
- if(!wbms)
- {
- DEBUG(0,("Out of memory in reply_readmpx\n"));
- return(ERROR(ERRSRV,ERRnoresource));
- }
- wbms->wr_mode = write_through;
- wbms->wr_discard = False; /* No errors yet */
- wbms->wr_total_written = nwritten;
- wbms->wr_errclass = 0;
- wbms->wr_error = 0;
- Files[fnum].wbmpx_ptr = wbms;
+ DEBUG(0,("Out of memory in reply_readmpx\n"));
+ return(ERROR(ERRSRV,ERRnoresource));
}
+ wbms->wr_mode = write_through;
+ wbms->wr_discard = False; /* No errors yet */
+ wbms->wr_total_written = nwritten;
+ wbms->wr_errclass = 0;
+ wbms->wr_error = 0;
+ fsp->wbmpx_ptr = wbms;
+ }
/* We are returning successfully, set the message type back to
SMBwritebmpx */
@@ -3025,13 +4296,13 @@ int reply_writebmpx(char *inbuf,char *outbuf)
SSVALS(outbuf,smb_vwv0,-1); /* We don't support smb_remaining */
- DEBUG(3,("%s writebmpx fnum=%d cnum=%d num=%d wrote=%d\n",
- timestring(),fnum,cnum,numtowrite,nwritten));
-
+ DEBUG( 3, ( "writebmpx fnum=%d num=%d wrote=%d\n",
+ fsp->fnum, (int)numtowrite, (int)nwritten ) );
+
if (write_through && tcount==nwritten) {
/* we need to send both a primary and a secondary response */
smb_setlen(outbuf,outsize - 4);
- send_smb(Client,outbuf);
+ send_smb(smbd_server_fd(),outbuf);
/* now the secondary */
outsize = set_message(outbuf,1,0,True);
@@ -3046,21 +4317,22 @@ int reply_writebmpx(char *inbuf,char *outbuf)
/****************************************************************************
reply to a SMBwritebs (write block multiplex secondary) request
****************************************************************************/
-int reply_writebs(char *inbuf,char *outbuf)
+int reply_writebs(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
{
- int cnum,numtowrite,fnum;
- int nwritten = -1;
+ size_t numtowrite;
+ ssize_t nwritten = -1;
int outsize = 0;
- int32 startpos;
- int tcount, write_through, smb_doff;
+ SMB_OFF_T startpos;
+ size_t tcount;
+ BOOL write_through;
+ int smb_doff;
char *data;
write_bmpx_struct *wbms;
- BOOL send_response = False;
-
- cnum = SVAL(inbuf,smb_tid);
- fnum = GETFNUM(inbuf,smb_vwv0);
- CHECK_FNUM(fnum,cnum);
- CHECK_WRITE(fnum);
+ BOOL send_response = False;
+ files_struct *fsp = file_fsp(inbuf,smb_vwv0);
+
+ CHECK_FSP(fsp,conn);
+ CHECK_WRITE(fsp);
tcount = SVAL(inbuf,smb_vwv1);
startpos = IVAL(inbuf,smb_vwv2);
@@ -3074,7 +4346,7 @@ int reply_writebs(char *inbuf,char *outbuf)
/* This fd should have an auxiliary struct attached,
check that it does */
- wbms = Files[fnum].wbmpx_ptr;
+ wbms = fsp->wbmpx_ptr;
if(!wbms) return(-1);
/* If write through is set we can return errors, else we must
@@ -3085,38 +4357,39 @@ int reply_writebs(char *inbuf,char *outbuf)
if(wbms->wr_discard)
return -1; /* Just discard the packet */
- seek_file(fnum,startpos);
- nwritten = write_file(fnum,data,numtowrite);
+ nwritten = write_file(fsp,data,startpos,numtowrite);
- if(lp_syncalways(SNUM(cnum)) || write_through)
- sync_file(fnum);
+ if(lp_syncalways(SNUM(conn)) || write_through)
+ sync_file(conn,fsp);
- if (nwritten < numtowrite)
+ if (nwritten < (ssize_t)numtowrite)
+ {
+ if(write_through)
{
- if(write_through) {
- /* We are returning an error - we can delete the aux struct */
- if (wbms) free((char *)wbms);
- Files[fnum].wbmpx_ptr = NULL;
- return(ERROR(ERRHRD,ERRdiskfull));
- }
- return(CACHE_ERROR(wbms,ERRHRD,ERRdiskfull));
+ /* We are returning an error - we can delete the aux struct */
+ if (wbms) free((char *)wbms);
+ fsp->wbmpx_ptr = NULL;
+ return(ERROR(ERRHRD,ERRdiskfull));
}
+ return(CACHE_ERROR(wbms,ERRHRD,ERRdiskfull));
+ }
/* Increment the total written, if this matches tcount
we can discard the auxiliary struct (hurrah !) and return a writeC */
wbms->wr_total_written += nwritten;
if(wbms->wr_total_written >= tcount)
+ {
+ if (write_through)
{
- if (write_through) {
- outsize = set_message(outbuf,1,0,True);
- SSVAL(outbuf,smb_vwv0,wbms->wr_total_written);
- send_response = True;
- }
-
- free((char *)wbms);
- Files[fnum].wbmpx_ptr = NULL;
+ outsize = set_message(outbuf,1,0,True);
+ SSVAL(outbuf,smb_vwv0,wbms->wr_total_written);
+ send_response = True;
}
+ free((char *)wbms);
+ fsp->wbmpx_ptr = NULL;
+ }
+
if(send_response)
return(outsize);
@@ -3127,19 +4400,17 @@ int reply_writebs(char *inbuf,char *outbuf)
/****************************************************************************
reply to a SMBsetattrE
****************************************************************************/
-int reply_setattrE(char *inbuf,char *outbuf)
+
+int reply_setattrE(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
{
- int cnum,fnum;
struct utimbuf unix_times;
int outsize = 0;
+ files_struct *fsp = file_fsp(inbuf,smb_vwv0);
outsize = set_message(outbuf,0,0,True);
- cnum = SVAL(inbuf,smb_tid);
- fnum = GETFNUM(inbuf,smb_vwv0);
-
- CHECK_FNUM(fnum,cnum);
- CHECK_ERROR(fnum);
+ CHECK_FSP(fsp,conn);
+ CHECK_ERROR(fsp);
/* Convert the DOS times into unix times. Ignore create
time as UNIX can't set this.
@@ -3147,11 +4418,33 @@ int reply_setattrE(char *inbuf,char *outbuf)
unix_times.actime = make_unix_date2(inbuf+smb_vwv3);
unix_times.modtime = make_unix_date2(inbuf+smb_vwv5);
+ /*
+ * Patch from Ray Frush <frush@engr.colostate.edu>
+ * Sometimes times are sent as zero - ignore them.
+ */
+
+ if ((unix_times.actime == 0) && (unix_times.modtime == 0))
+ {
+ /* Ignore request */
+ if( DEBUGLVL( 3 ) )
+ {
+ dbgtext( "reply_setattrE fnum=%d ", fsp->fnum);
+ dbgtext( "ignoring zero request - not setting timestamps of 0\n" );
+ }
+ return(outsize);
+ }
+ else if ((unix_times.actime != 0) && (unix_times.modtime == 0))
+ {
+ /* set modify time = to access time if modify time was 0 */
+ unix_times.modtime = unix_times.actime;
+ }
+
/* Set the date on this file */
- if(sys_utime(Files[fnum].name, &unix_times))
+ if(file_utime(conn, fsp->fsp_name, &unix_times))
return(ERROR(ERRDOS,ERRnoaccess));
- DEBUG(3,("%s reply_setattrE fnum=%d cnum=%d\n",timestring(),fnum,cnum));
+ DEBUG( 3, ( "reply_setattrE fnum=%d actime=%d modtime=%d\n",
+ fsp->fnum, (int)unix_times.actime, (int)unix_times.modtime ) );
return(outsize);
}
@@ -3160,31 +4453,29 @@ int reply_setattrE(char *inbuf,char *outbuf)
/****************************************************************************
reply to a SMBgetattrE
****************************************************************************/
-int reply_getattrE(char *inbuf,char *outbuf)
+
+int reply_getattrE(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
{
- int cnum,fnum;
- struct stat sbuf;
+ SMB_STRUCT_STAT sbuf;
int outsize = 0;
int mode;
+ files_struct *fsp = file_fsp(inbuf,smb_vwv0);
outsize = set_message(outbuf,11,0,True);
- cnum = SVAL(inbuf,smb_tid);
- fnum = GETFNUM(inbuf,smb_vwv0);
-
- CHECK_FNUM(fnum,cnum);
- CHECK_ERROR(fnum);
+ CHECK_FSP(fsp,conn);
+ CHECK_ERROR(fsp);
/* Do an fstat on this file */
- if(fstat(Files[fnum].fd, &sbuf))
+ if(fsp->conn->vfs_ops.fstat(fsp->fd, &sbuf))
return(UNIXERROR(ERRDOS,ERRnoaccess));
- mode = dos_mode(cnum,Files[fnum].name,&sbuf);
+ mode = dos_mode(conn,fsp->fsp_name,&sbuf);
/* Convert the times into dos times. Set create
date to be last modify date as UNIX doesn't save
this */
- put_dos_date2(outbuf,smb_vwv0,sbuf.st_mtime);
+ put_dos_date2(outbuf,smb_vwv0,get_create_time(&sbuf,lp_fake_dir_create_times(SNUM(conn))));
put_dos_date2(outbuf,smb_vwv2,sbuf.st_atime);
put_dos_date2(outbuf,smb_vwv4,sbuf.st_mtime);
if (mode & aDIR)
@@ -3194,17 +4485,13 @@ int reply_getattrE(char *inbuf,char *outbuf)
}
else
{
- SIVAL(outbuf,smb_vwv6,sbuf.st_size);
- SIVAL(outbuf,smb_vwv8,ROUNDUP(sbuf.st_size,1024));
+ SIVAL(outbuf,smb_vwv6,(uint32)sbuf.st_size);
+ SIVAL(outbuf,smb_vwv8,SMB_ROUNDUP(sbuf.st_size,1024));
}
SSVAL(outbuf,smb_vwv10, mode);
- DEBUG(3,("%s reply_getattrE fnum=%d cnum=%d\n",timestring(),fnum,cnum));
+ DEBUG( 3, ( "reply_getattrE fnum=%d\n", fsp->fnum));
return(outsize);
}
-
-
-
-
-
+#undef OLD_NTDOMAIN