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.c2401
1 files changed, 1582 insertions, 819 deletions
diff --git a/source/smbd/reply.c b/source/smbd/reply.c
index 845fabda926..8e97857ef68 100644
--- a/source/smbd/reply.c
+++ b/source/smbd/reply.c
@@ -3,8 +3,7 @@
Version 1.9.
Main SMB reply routines
Copyright (C) Andrew Tridgell 1992-1998
- Copyright (C) Andrew Bartlett 2001
-
+
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
the Free Software Foundation; either version 2 of the License, or
@@ -29,6 +28,7 @@
/* look in server.c for some explanation of these variables */
extern int Protocol;
+extern int DEBUGLEVEL;
extern int max_send;
extern int max_recv;
extern char magic_char;
@@ -37,12 +37,24 @@ extern BOOL case_preserve;
extern BOOL short_case_preserve;
extern userdom_struct current_user_info;
extern pstring global_myname;
+extern fstring global_myworkgroup;
extern int global_oplock_break;
uint32 global_client_caps = 0;
unsigned int smb_echo_count = 0;
-extern fstring remote_machine;
-extern BOOL global_encrypted_passwords_negotiated;
+/****************************************************************************
+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() );
+ }
+}
/****************************************************************************
@@ -55,7 +67,7 @@ int reply_special(char *inbuf,char *outbuf)
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;
@@ -106,9 +118,8 @@ int reply_special(char *inbuf,char *outbuf)
break;
}
- /* only add the client's machine name to the list
- of possibly valid usernames if we are operating
- in share mode security */
+ /* add it as a possible user name if we
+ are in share mode security */
if (lp_security() == SEC_SHARE) {
add_session_user(remote_machine);
}
@@ -116,7 +127,9 @@ int reply_special(char *inbuf,char *outbuf)
reload_services(True);
reopen_logs();
- claim_connection(NULL,"",MAXSTATUS,True);
+ if (lp_status(-1)) {
+ claim_connection(NULL,"",MAXSTATUS,True);
+ }
break;
@@ -144,6 +157,53 @@ int reply_special(char *inbuf,char *outbuf)
}
+/*******************************************************************
+work out what error to give to a failed connection
+********************************************************************/
+
+static int connection_error(char *inbuf,char *outbuf,int ecode)
+{
+ if (ecode == ERRnoipc || ecode == ERRnosuchshare)
+ return(ERROR(ERRDOS,ecode));
+
+ return(ERROR(ERRSRV,ecode));
+}
+
+/****************************************************************************
+ 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);
+
+ p += strlen(p) + 2;
+
+ fstrcpy(password,p);
+ *pwlen = strlen(password);
+
+ p += strlen(p) + 2;
+
+ fstrcpy(dev,p);
+
+ *user = 0;
+ p = strchr(service,'%');
+ if (p != NULL)
+ {
+ *p = 0;
+ fstrcpy(user,p+1);
+ }
+}
+
/****************************************************************************
Reply to a tcon.
****************************************************************************/
@@ -151,34 +211,54 @@ int reply_special(char *inbuf,char *outbuf)
int reply_tcon(connection_struct *conn,
char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
{
+ BOOL doencrypt = SMBENCRYPT();
pstring service;
+ pstring user;
pstring password;
pstring dev;
int outsize = 0;
uint16 vuid = SVAL(inbuf,smb_uid);
int pwlen=0;
- NTSTATUS nt_status;
- char *p;
-
+ int ecode = -1;
START_PROFILE(SMBtcon);
- *service = *password = *dev = 0;
+ *service = *user = *password = *dev = 0;
- p = smb_buf(inbuf)+1;
- p += srvstr_pull(inbuf, service, p, sizeof(service), -1, STR_TERMINATE) + 1;
- p += srvstr_pull(inbuf, password, p, sizeof(password), -1, STR_TERMINATE) + 1;
- p += srvstr_pull(inbuf, dev, p, sizeof(dev), -1, STR_TERMINATE) + 1;
+ parse_connect(smb_buf(inbuf)+1,service,user,password,&pwlen,dev);
- p = strrchr_m(service,'\\');
- if (p) {
- pstrcpy(service, p+1);
+ /*
+ * If the vuid is valid, we should be using that....
+ */
+
+ if (*user == '\0' && (lp_security() != SEC_SHARE) && validated_username(vuid)) {
+ pstrcpy(user,validated_username(vuid));
}
- conn = make_connection(service,password,pwlen,dev,vuid,&nt_status);
+ /*
+ * Ensure the user and password names are in UNIX codepage format.
+ */
+
+ pstrcpy(user,dos_to_unix(user,False));
+ if (!doencrypt)
+ pstrcpy(password,dos_to_unix(password,False));
+
+ /*
+ * 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,pwlen,dev,vuid,&ecode);
if (!conn) {
END_PROFILE(SMBtcon);
- return ERROR_NT(nt_status);
+ return(connection_error(inbuf,outbuf,ecode));
}
outsize = set_message(outbuf,2,0,True);
@@ -186,8 +266,8 @@ int reply_tcon(connection_struct *conn,
SSVAL(outbuf,smb_vwv1,conn->cnum);
SSVAL(outbuf,smb_tid,conn->cnum);
- DEBUG(3,("tcon service=%s cnum=%d\n",
- service, conn->cnum));
+ DEBUG(3,("tcon service=%s user=%s cnum=%d\n",
+ service, user, conn->cnum));
END_PROFILE(SMBtcon);
return(outsize);
@@ -200,16 +280,18 @@ int reply_tcon(connection_struct *conn,
int reply_tcon_and_X(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
{
fstring service;
+ pstring user;
pstring password;
pstring devicename;
- NTSTATUS nt_status;
+ BOOL doencrypt = SMBENCRYPT();
+ int ecode = -1;
uint16 vuid = SVAL(inbuf,smb_uid);
int passlen = SVAL(inbuf,smb_vwv3);
- pstring path;
- char *p, *q;
+ char *path;
+ char *p;
START_PROFILE(SMBtconX);
- *service = *password = *devicename = 0;
+ *service = *user = *password = *devicename = 0;
/* we might have to close an old one */
if ((SVAL(inbuf,smb_vwv2) & 0x1) && conn) {
@@ -217,65 +299,91 @@ int reply_tcon_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
}
if (passlen > MAX_PASS_LEN) {
- return ERROR_DOS(ERRDOS,ERRbuftoosmall);
+ overflow_attack(passlen);
+ return(ERROR(ERRDOS,ERRbuftoosmall));
}
memcpy(password,smb_buf(inbuf),passlen);
password[passlen]=0;
- p = smb_buf(inbuf) + passlen;
- p += srvstr_pull(inbuf, path, p, sizeof(path), -1, STR_TERMINATE);
+ path = smb_buf(inbuf) + passlen;
if (passlen != 24) {
if (strequal(password," "))
*password = 0;
passlen = strlen(password);
}
-
+
/*
* the service name can be either: \\server\share
* or share directly like on the DELL PowerVault 705
*/
if (*path=='\\') {
- q = strchr_m(path+2,'\\');
- if (!q) {
+ p = strchr(path+2,'\\');
+ if (!p) {
END_PROFILE(SMBtconX);
- return(ERROR_DOS(ERRDOS,ERRnosuchshare));
+ return(ERROR(ERRDOS,ERRnosuchshare));
}
- fstrcpy(service,q+1);
+ fstrcpy(service,p+1);
}
else
fstrcpy(service,path);
- p += srvstr_pull(inbuf, devicename, p, sizeof(devicename), 6, STR_ASCII);
-
+ 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));
- conn = make_connection(service,password,passlen,devicename,vuid,&nt_status);
+ /*
+ * If the vuid is valid, we should be using that....
+ */
+
+ if (*user == '\0' && (lp_security() != SEC_SHARE) && validated_username(vuid)) {
+ pstrcpy(user,validated_username(vuid));
+ }
+
+ /*
+ * Ensure the user and password names are in UNIX codepage format.
+ */
+
+ pstrcpy(user,dos_to_unix(user,False));
+ if (!doencrypt)
+ pstrcpy(password,dos_to_unix(password,False));
+
+ /*
+ * 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) {
END_PROFILE(SMBtconX);
- return ERROR_NT(nt_status);
+ return(connection_error(inbuf,outbuf,ecode));
}
if (Protocol < PROTOCOL_NT1) {
- set_message(outbuf,2,0,True);
- p = smb_buf(outbuf);
- p += srvstr_push(outbuf, p, devicename, -1,
- STR_TERMINATE|STR_ASCII);
- set_message_end(outbuf,p);
+ set_message(outbuf,2,strlen(devicename)+1,True);
+ pstrcpy(smb_buf(outbuf),devicename);
} else {
- /* NT sets the fstype of IPC$ to the null string */
- char *fsname = IS_IPC(conn) ? "" : lp_fstype(SNUM(conn));
+ char *fsname = lp_fstype(SNUM(conn));
- set_message(outbuf,3,0,True);
+ set_message(outbuf,3,3,True);
p = smb_buf(outbuf);
- p += srvstr_push(outbuf, p, devicename, -1,
- STR_TERMINATE|STR_ASCII);
- p += srvstr_push(outbuf, p, fsname, -1,
- STR_TERMINATE);
+ 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_end(outbuf,p);
+ 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 */
@@ -285,8 +393,8 @@ int reply_tcon_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
}
- DEBUG(3,("tconX service=%s \n",
- service));
+ 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);
@@ -308,10 +416,9 @@ int reply_unknown(char *inbuf,char *outbuf)
DEBUG(0,("unknown command type (%s): type=%d (0x%X)\n",
smb_fn_name(type), type, type));
- return(ERROR_DOS(ERRSRV,ERRunknownsmb));
+ return(ERROR(ERRSRV,ERRunknownsmb));
}
-
/****************************************************************************
reply to an ioctl
****************************************************************************/
@@ -335,7 +442,7 @@ int reply_ioctl(connection_struct *conn,
break;
default:
END_PROFILE(SMBioctl);
- return(ERROR_DOS(ERRSRV,ERRnosupport));
+ return(ERROR(ERRSRV,ERRnosupport));
}
outsize = set_message(outbuf,8,replysize+1,True);
@@ -348,8 +455,8 @@ int reply_ioctl(connection_struct *conn,
{
case IOCTL_QUERY_JOB_INFO:
SSVAL(p,0,fsp->print_jobid); /* Job number */
- srvstr_push(outbuf, p+2, global_myname, 15, STR_TERMINATE|STR_ASCII);
- srvstr_push(outbuf, p+18, lp_servicename(SNUM(conn)), 13, STR_TERMINATE|STR_ASCII);
+ StrnCpy(p+2, global_myname, 15); /* Our NetBIOS name */
+ StrnCpy(p+18, lp_servicename(SNUM(conn)), 13); /* Service name */
break;
}
@@ -358,6 +465,632 @@ int reply_ioctl(connection_struct *conn,
}
/****************************************************************************
+ Always return an error: it's just a matter of which one...
+ FIXME: memory leak - no call to pdb_free_sam() --jerry
+ ****************************************************************************/
+
+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)
+{
+ SAM_ACCOUNT *sam_trust_acct = NULL; /* check if trust account exists */
+ uint16 acct_ctrl;
+
+ if (lp_security() == SEC_USER) {
+ pdb_init_sam(&sam_trust_acct);
+ pdb_getsampwnam(sam_trust_acct, user);
+ } else {
+ DEBUG(0,("session_trust_account: Trust account %s only supported with security = user\n", user));
+ return(ERROR_BOTH(NT_STATUS_LOGON_FAILURE,ERRSRV,ERRbadpw));
+ }
+
+ if (sam_trust_acct == NULL) {
+ /* lkclXXXX: workstation entry doesn't exist */
+ DEBUG(0,("session_trust_account: Trust account %s user doesn't exist\n",user));
+ return(ERROR_BOTH(NT_STATUS_NO_SUCH_USER,ERRDOS,1317));
+ } else {
+ if ((smb_passlen != 24) || (smb_nt_passlen != 24)) {
+ DEBUG(0,("session_trust_account: Trust account %s - password length wrong.\n", user));
+ return(ERROR_BOTH(NT_STATUS_LOGON_FAILURE,ERRSRV,ERRbadpw));
+ }
+
+ if (!smb_password_ok(sam_trust_acct, NULL, (unsigned char *)smb_passwd, (unsigned char *)smb_nt_passwd)) {
+ DEBUG(0,("session_trust_account: Trust Account %s - password failed\n", user));
+ return(ERROR_BOTH(NT_STATUS_LOGON_FAILURE,ERRSRV,ERRbadpw));
+ }
+
+ acct_ctrl = pdb_get_acct_ctrl(sam_trust_acct);
+ if (acct_ctrl & ACB_DOMTRUST) {
+ DEBUG(0,("session_trust_account: Domain trust account %s denied by server\n",user));
+ return(ERROR_BOTH(NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT,ERRDOS,1807));
+ }
+
+ if (acct_ctrl & ACB_SVRTRUST) {
+ DEBUG(0,("session_trust_account: Server trust account %s denied by server\n",user));
+ return(ERROR_BOTH(NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT,ERRDOS,1809));
+ }
+
+ if (acct_ctrl & ACB_WSTRUST) {
+ DEBUG(4,("session_trust_account: Wksta trust account %s denied by server\n", user));
+ return(ERROR_BOTH(NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT,ERRDOS,1808));
+ }
+ }
+
+ /* don't know what to do: indicate logon failure */
+ return(ERROR_BOTH(NT_STATUS_LOGON_FAILURE,ERRDOS,1326));
+}
+
+/****************************************************************************
+ Create a UNIX user on demand.
+****************************************************************************/
+
+int smb_create_user(char *unix_user, char *homedir)
+{
+ pstring add_script;
+ int ret;
+
+ pstrcpy(add_script, lp_adduser_script());
+ if (! *add_script) return -1;
+ all_string_sub(add_script, "%u", unix_user, sizeof(pstring));
+ if (homedir)
+ all_string_sub(add_script, "%H", homedir, sizeof(pstring));
+ ret = smbrun(add_script,NULL);
+ 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;
+ all_string_sub(del_script, "%u", unix_user, sizeof(pstring));
+ ret = smbrun(del_script,NULL);
+ 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) {
+ struct passwd *pwd = NULL;
+
+ /*
+ * 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() && !(pwd = smb_getpwnam(unix_user,True)))
+ smb_create_user(unix_user, NULL);
+
+ if(lp_adduser_script() && pwd) {
+ SMB_STRUCT_STAT st;
+
+ /*
+ * Also call smb_create_user if the users home directory
+ * doesn't exist. Used with winbindd to allow the script to
+ * create the home directory for a user mapped with winbindd.
+ */
+
+ if (pwd->pw_dir && (sys_stat(pwd->pw_dir, &st) == -1) && (errno == ENOENT))
+ smb_create_user(unix_user, pwd->pw_dir);
+ }
+ }
+
+ 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;
+ struct passwd *pwd = NULL;
+
+ 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() && !(pwd = smb_getpwnam(unix_user,True))) {
+ smb_create_user(unix_user, NULL);
+ }
+
+ if(lp_adduser_script() && pwd) {
+ SMB_STRUCT_STAT st;
+
+ /*
+ * Also call smb_create_user if the users home directory
+ * doesn't exist. Used with winbindd to allow the script to
+ * create the home directory for a user mapped with winbindd.
+ */
+
+ if (pwd->pw_dir && (sys_stat(pwd->pw_dir, &st) == -1) && (errno == ENOENT))
+ smb_create_user(unix_user, pwd->pw_dir);
+ }
+
+ } 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;
+}
+
+/****************************************************************************
+ Reply to a session setup command.
+****************************************************************************/
+
+int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
+{
+ int sess_vuid;
+ gid_t gid;
+ uid_t uid;
+ int smb_bufsize;
+ int smb_apasslen = 0;
+ pstring smb_apasswd;
+ int smb_ntpasslen = 0;
+ pstring smb_ntpasswd;
+ BOOL valid_nt_password = False;
+ BOOL valid_lm_password = False;
+ pstring user;
+ pstring orig_user;
+ BOOL guest=False;
+ static BOOL done_sesssetup = False;
+ BOOL doencrypt = SMBENCRYPT();
+ fstring domain;
+ START_PROFILE(SMBsesssetupX);
+
+ *smb_apasswd = 0;
+ *smb_ntpasswd = 0;
+ *domain = 0;
+
+ smb_bufsize = SVAL(inbuf,smb_vwv2);
+
+ if (Protocol < PROTOCOL_NT1) {
+ smb_apasslen = SVAL(inbuf,smb_vwv7);
+ if (smb_apasslen > MAX_PASS_LEN) {
+ overflow_attack(smb_apasslen);
+ return(ERROR(ERRDOS,ERRbuftoosmall));
+ }
+
+ memcpy(smb_apasswd,smb_buf(inbuf),smb_apasslen);
+ smb_apasswd[smb_apasslen] = 0;
+ pstrcpy(user,smb_buf(inbuf)+smb_apasslen);
+ /*
+ * Incoming user is in DOS codepage format. Convert
+ * to UNIX.
+ */
+ pstrcpy(user,dos_to_unix(user,False));
+
+ if (!doencrypt && (lp_security() != SEC_SERVER)) {
+ smb_apasslen = strlen(smb_apasswd);
+ }
+ } else {
+ uint16 passlen1 = SVAL(inbuf,smb_vwv7);
+ uint16 passlen2 = SVAL(inbuf,smb_vwv8);
+ 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);
+ return(ERROR(ERRDOS,ERRbuftoosmall));
+ }
+
+ 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) {
+ pstrcpy(smb_apasswd,dos_to_unix(smb_apasswd,False));
+ pstrcpy(smb_ntpasswd,dos_to_unix(smb_ntpasswd,False));
+ }
+
+ } else {
+ /* 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.
+ */
+ pstrcpy(smb_apasswd,dos_to_unix(smb_apasswd,False));
+
+ /* 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;
+ }
+ }
+
+ p += passlen1 + passlen2;
+ fstrcpy(user,p);
+ p = skip_string(p,1);
+ /*
+ * Incoming user and domain are in DOS codepage format. Convert
+ * to UNIX.
+ */
+ pstrcpy(user,dos_to_unix(user,False));
+ fstrcpy(domain, dos_to_unix(p, False));
+ DEBUG(3,("Domain=[%s] NativeOS=[%s] NativeLanMan=[%s]\n",
+ domain,skip_string(p,1),skip_string(p,2)));
+ }
+
+ /* don't allow strange characters in usernames or domains */
+ alpha_strcpy(user, user, ". _-$", sizeof(user));
+ alpha_strcpy(domain, domain, ". _-", sizeof(domain));
+ if (strstr(user, "..") || strstr(domain,"..")) {
+ return ERROR_BOTH(NT_STATUS_LOGON_FAILURE,ERRSRV,ERRbadpw);
+ }
+
+ DEBUG(3,("sesssetupX:name=[%s]\n",user));
+
+ /* 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 $. */
+
+ if (*user && (user[strlen(user) - 1] == '$') && (smb_apasslen == 24) && (smb_ntpasslen == 24)) {
+ END_PROFILE(SMBsesssetupX);
+ return session_trust_account(conn, inbuf, outbuf, user,
+ smb_apasswd, smb_apasslen,
+ smb_ntpasswd, smb_ntpasslen);
+ }
+
+ 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"));
+ END_PROFILE(SMBsesssetupX);
+ return(ERROR(ERRDOS,ERRnoaccess));
+ }
+ }
+
+ /* If no username is sent use the guest account */
+ if (!*user) {
+ pstrcpy(user,lp_guestaccount(-1));
+ guest = True;
+ }
+
+ pstrcpy(current_user_info.smb_name,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);
+
+ /*
+ * Always try the "DOMAIN\user" lookup first, as this is the most
+ * specific case. If this fails then try the simple "user" lookup.
+ */
+
+ {
+ pstring dom_user;
+
+ /* Work out who's who */
+
+ slprintf(dom_user, sizeof(dom_user) - 1,"%s%s%s",
+ dos_to_unix(domain, False), lp_winbind_separator(), user);
+
+ if (sys_getpwnam(dom_user) != NULL) {
+ pstrcpy(user, dom_user);
+ DEBUG(3,("Using unix username %s\n", dom_user));
+ }
+ }
+
+ /*
+ * 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 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 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'!\n", user));
+ else
+ valid_nt_password = True;
+ }
+
+
+ /* check the LanMan password only if necessary and if allowed
+ by lp_lanman_auth() */
+ if (!valid_nt_password && lp_lanman_auth())
+ {
+ DEBUG(2,("Defaulting to Lanman password for %s\n", user));
+ valid_lm_password = password_ok(user, smb_apasswd,smb_apasslen,NULL);
+ }
+
+
+ /* The true branch will be executed if
+ (1) the NT password failed (or was not tried), and
+ (2) LanMan authentication failed (or was disabled)
+ */
+ if (!valid_nt_password && !valid_lm_password)
+ {
+ if (lp_security() >= SEC_USER)
+ {
+ if (lp_map_to_guest() == NEVER_MAP_TO_GUEST)
+ {
+ DEBUG(1,("Rejecting user '%s': authentication failed\n", user));
+ END_PROFILE(SMBsesssetupX);
+ return ERROR_BOTH(NT_STATUS_LOGON_FAILURE,ERRSRV,ERRbadpw);
+ }
+
+ 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));
+ END_PROFILE(SMBsesssetupX);
+ return ERROR_BOTH(NT_STATUS_LOGON_FAILURE,ERRSRV,ERRbadpw);
+ }
+ }
+
+ /*
+ * ..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 (!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)
+ {
+ add_home_service(user,get_user_home_dir(user));
+ }
+
+
+ /* it's ok - setup a reply */
+ if (Protocol < PROTOCOL_NT1) {
+ set_message(outbuf,3,0,True);
+ } else {
+ char *p;
+ set_message(outbuf,3,3,True);
+ p = smb_buf(outbuf);
+ pstrcpy(p,"Unix"); p = skip_string(p,1);
+ pstrcpy(p,"Samba "); pstrcat(p,VERSION); p = skip_string(p,1);
+ pstrcpy(p,global_myworkgroup); unix_to_dos(p, True); p = skip_string(p,1);
+ set_message(outbuf,3,PTR_DIFF(p,smb_buf(outbuf)),False);
+ /* perhaps grab OS version here?? */
+ }
+
+ /* Set the correct uid in the outgoing and incoming packets
+ We will use this on future requests to determine which
+ user we should become.
+ */
+ {
+ const struct passwd *pw = smb_getpwnam(user,False);
+ if (!pw) {
+ DEBUG(1,("Username %s is invalid on this system\n",user));
+ END_PROFILE(SMBsesssetupX);
+ return ERROR_BOTH(NT_STATUS_LOGON_FAILURE,ERRSRV,ERRbadpw);
+ }
+ gid = pw->pw_gid;
+ uid = pw->pw_uid;
+ }
+
+ 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 */
+
+ sess_vuid = register_vuid(uid,gid,user,current_user_info.smb_name,domain,guest);
+
+ if (sess_vuid == -1) {
+ return(ERROR(ERRDOS,ERRnoaccess));
+ }
+
+
+ SSVAL(outbuf,smb_uid,sess_vuid);
+ SSVAL(inbuf,smb_uid,sess_vuid);
+
+ if (!done_sesssetup)
+ max_send = MIN(max_send,smb_bufsize);
+
+ DEBUG(6,("Client requested max send size of %d\n", max_send));
+
+ done_sesssetup = True;
+
+ END_PROFILE(SMBsesssetupX);
+ return chain_reply(inbuf,outbuf,length,bufsize);
+}
+
+
+/****************************************************************************
reply to a chkpth
****************************************************************************/
int reply_chkpth(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
@@ -369,8 +1102,8 @@ int reply_chkpth(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
BOOL bad_path = False;
SMB_STRUCT_STAT sbuf;
START_PROFILE(SMBchkpth);
-
- srvstr_pull(inbuf, name, smb_buf(inbuf) + 1, sizeof(name), -1, STR_TERMINATE);
+
+ pstrcpy(name,smb_buf(inbuf) + 1);
RESOLVE_DFSPATH(name, conn, inbuf, outbuf);
@@ -383,16 +1116,29 @@ int reply_chkpth(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
ok = S_ISDIR(sbuf.st_mode);
}
- if (!ok) {
+ if (!ok)
+ {
/* 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) {
- return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
+ 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));
}
@@ -418,11 +1164,9 @@ int reply_getatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
SMB_OFF_T size=0;
time_t mtime=0;
BOOL bad_path = False;
- char *p;
START_PROFILE(SMBgetatr);
-
- p = smb_buf(inbuf) + 1;
- p += srvstr_pull(inbuf, fname, p, sizeof(fname), -1, STR_TERMINATE);
+
+ pstrcpy(fname,smb_buf(inbuf) + 1);
RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
@@ -477,7 +1221,11 @@ int reply_getatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
SIVAL(outbuf,smb_vwv3,(uint32)size);
if (Protocol >= PROTOCOL_NT1) {
- SSVAL(outbuf,smb_flg2,SVAL(outbuf, smb_flg2) | 0x40); /* IS_LONG_NAME */
+ char *p = strrchr(fname,'/');
+ uint16 flg2 = SVAL(outbuf,smb_flg2);
+ if (!p) p = fname;
+ if (!is_8_3(fname, True))
+ SSVAL(outbuf,smb_flg2,flg2 | 0x40); /* IS_LONG_NAME */
}
DEBUG( 3, ( "getatr name=%s mode=%d size=%d\n", fname, mode, (uint32)size ) );
@@ -499,12 +1247,9 @@ int reply_setatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
time_t mtime;
SMB_STRUCT_STAT sbuf;
BOOL bad_path = False;
- char *p;
-
START_PROFILE(SMBsetatr);
-
- p = smb_buf(inbuf) + 1;
- p += srvstr_pull(inbuf, fname, p, sizeof(fname), -1, STR_TERMINATE);
+
+ pstrcpy(fname,smb_buf(inbuf) + 1);
unix_convert(fname,conn,0,&bad_path,&sbuf);
mode = SVAL(inbuf,smb_vwv0);
@@ -584,7 +1329,7 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
char *p;
BOOL ok = False;
int status_len;
- pstring path;
+ char *path;
char status[21];
int dptr_num= -1;
BOOL check_descend = False;
@@ -602,28 +1347,26 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
outsize = set_message(outbuf,1,3,True);
maxentries = SVAL(inbuf,smb_vwv0);
dirtype = SVAL(inbuf,smb_vwv1);
- p = smb_buf(inbuf) + 1;
- p += srvstr_pull(inbuf, path, p, sizeof(path), -1, STR_TERMINATE);
- p++;
- status_len = SVAL(p, 0);
- p += 2;
-
+ path = smb_buf(inbuf) + 1;
+ status_len = SVAL(smb_buf(inbuf),3 + strlen(path));
+
+ RESOLVE_DFSPATH(path, conn, inbuf, outbuf);
/* dirtype &= ~aDIR; */
-
+
if (status_len == 0)
{
SMB_STRUCT_STAT sbuf;
pstring dir2;
- pstrcpy(directory,path);
- pstrcpy(dir2,path);
+ pstrcpy(directory,smb_buf(inbuf)+1);
+ pstrcpy(dir2,smb_buf(inbuf)+1);
unix_convert(directory,conn,0,&bad_path,&sbuf);
unix_format(dir2);
if (!check_name(directory,conn))
can_open = False;
- p = strrchr_m(dir2,'/');
+ p = strrchr(dir2,'/');
if (p == NULL)
{
pstrcpy(mask,dir2);
@@ -635,7 +1378,7 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
pstrcpy(mask,p+1);
}
- p = strrchr_m(directory,'/');
+ p = strrchr(directory,'/');
if (!p)
*directory = 0;
else
@@ -648,7 +1391,7 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
}
else
{
- memcpy(status,p,21);
+ 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)
@@ -679,7 +1422,7 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
return (UNIXERROR(ERRDOS,ERRnofids));
}
END_PROFILE(SMBsearch);
- return ERROR_DOS(ERRDOS,ERRnofids);
+ return(ERROR(ERRDOS,ERRnofids));
}
dptr_set_wcard(dptr_num, strdup(mask));
}
@@ -726,11 +1469,11 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
SearchEmpty:
- if (numentries == 0 || !ok)
+ if ( (numentries == 0) || !ok)
{
- CVAL(outbuf,smb_rcls) = ERRDOS;
- SSVAL(outbuf,smb_err,ERRnofiles);
- dptr_close(&dptr_num);
+ 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
@@ -755,9 +1498,10 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
SSVAL(smb_buf(outbuf),1,numentries*DIR_STRUCT_SIZE);
if (Protocol >= PROTOCOL_NT1) {
- SSVAL(outbuf,smb_flg2,SVAL(outbuf, smb_flg2) | 0x40); /* IS_LONG_NAME */
+ uint16 flg2 = SVAL(outbuf,smb_flg2);
+ SSVAL(outbuf,smb_flg2,flg2 | 0x40); /* IS_LONG_NAME */
}
-
+
outsize += DIR_STRUCT_SIZE*numentries;
smb_setlen(outbuf,outsize - 4);
@@ -780,26 +1524,22 @@ int reply_fclose(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
{
int outsize = 0;
int status_len;
- pstring path;
+ char *path;
char status[21];
int dptr_num= -2;
- char *p;
-
START_PROFILE(SMBfclose);
outsize = set_message(outbuf,1,0,True);
- p = smb_buf(inbuf) + 1;
- p += srvstr_pull(inbuf, path, p, sizeof(path), -1, STR_TERMINATE);
- p++;
- status_len = SVAL(p,0);
- p += 2;
+ path = smb_buf(inbuf) + 1;
+ status_len = SVAL(smb_buf(inbuf),3 + strlen(path));
+
if (status_len == 0) {
END_PROFILE(SMBfclose);
- return ERROR_DOS(ERRSRV,ERRsrverror);
+ return(ERROR(ERRSRV,ERRsrverror));
}
- memcpy(status,p,21);
+ memcpy(status,smb_buf(inbuf) + 1 + strlen(path) + 4,21);
if(dptr_fetch(status+12,&dptr_num)) {
/* Close the dptr - we know it's gone */
@@ -837,7 +1577,7 @@ int reply_open(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
share_mode = SVAL(inbuf,smb_vwv0);
- srvstr_pull(inbuf, fname, smb_buf(inbuf)+1, sizeof(fname), -1, STR_TERMINATE);
+ pstrcpy(fname,smb_buf(inbuf)+1);
RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
@@ -867,7 +1607,7 @@ int reply_open(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
DEBUG(3,("attempt to open a directory %s\n",fname));
close_file(fsp,False);
END_PROFILE(SMBopen);
- return ERROR_DOS(ERRDOS,ERRnoaccess);
+ return(ERROR(ERRDOS,ERRnoaccess));
}
outsize = set_message(outbuf,7,0,True);
@@ -926,12 +1666,13 @@ int reply_open_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
return reply_open_pipe_and_X(conn, inbuf,outbuf,length,bufsize);
} else {
END_PROFILE(SMBopenX);
- return ERROR_DOS(ERRSRV,ERRaccess);
+ return (ERROR(ERRSRV,ERRaccess));
}
}
/* XXXX we need to handle passed times, sattr and flags */
- srvstr_pull(inbuf, fname, smb_buf(inbuf), sizeof(fname), -1, STR_TERMINATE);
+
+ pstrcpy(fname,smb_buf(inbuf));
RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
@@ -959,7 +1700,7 @@ int reply_open_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
if (fmode & aDIR) {
close_file(fsp,False);
END_PROFILE(SMBopenX);
- return ERROR_DOS(ERRDOS,ERRnoaccess);
+ return(ERROR(ERRDOS,ERRnoaccess));
}
/* If the caller set the extended oplock request bit
@@ -1054,7 +1795,7 @@ int reply_mknew(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
com = SVAL(inbuf,smb_com);
createmode = SVAL(inbuf,smb_vwv0);
- srvstr_pull(inbuf, fname, smb_buf(inbuf) + 1, sizeof(fname), -1, STR_TERMINATE);
+ pstrcpy(fname,smb_buf(inbuf)+1);
RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
@@ -1116,115 +1857,107 @@ int reply_mknew(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
****************************************************************************/
int reply_ctemp(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
{
- pstring fname;
- int outsize = 0;
- int createmode;
- mode_t unixmode;
- BOOL bad_path = False;
- files_struct *fsp;
- int oplock_request = CORE_OPLOCK_REQUEST(inbuf);
- int tmpfd;
- SMB_STRUCT_STAT sbuf;
- char *p, *s;
+ pstring fname;
+ int outsize = 0;
+ int createmode;
+ mode_t unixmode;
+ BOOL bad_path = False;
+ files_struct *fsp;
+ int oplock_request = CORE_OPLOCK_REQUEST(inbuf);
+ int tmpfd;
+ SMB_STRUCT_STAT sbuf;
+ char *p, *s;
- START_PROFILE(SMBctemp);
+ START_PROFILE(SMBctemp);
- createmode = SVAL(inbuf,smb_vwv0);
- srvstr_pull(inbuf, fname, smb_buf(inbuf)+1, sizeof(fname), -1, STR_TERMINATE);
- pstrcat(fname,"\\TMXXXXXX");
+ createmode = SVAL(inbuf,smb_vwv0);
+ pstrcpy(fname,smb_buf(inbuf)+1);
+ pstrcat(fname,"\\TMXXXXXX");
- RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
+ RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
- unix_convert(fname,conn,0,&bad_path,&sbuf);
-
- unixmode = unix_mode(conn,createmode,fname);
-
- tmpfd = smb_mkstemp(fname);
- if (tmpfd == -1) {
- END_PROFILE(SMBctemp);
- return(UNIXERROR(ERRDOS,ERRnoaccess));
- }
+ unix_convert(fname,conn,0,&bad_path,&sbuf);
- vfs_stat(conn,fname,&sbuf);
+ unixmode = unix_mode(conn,createmode,fname);
- /* Open file in dos compatibility share mode. */
- /* We should fail if file does not exist. */
- fsp = open_file_shared(conn,fname,&sbuf,
- SET_DENY_MODE(DENY_FCB)|SET_OPEN_MODE(DOS_OPEN_FCB),
- FILE_EXISTS_OPEN|FILE_FAIL_IF_NOT_EXIST,
- unixmode, oplock_request, NULL, NULL);
+ tmpfd = smb_mkstemp(fname);
+ if (tmpfd == -1) {
+ END_PROFILE(SMBctemp);
+ return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
- /* close fd from smb_mkstemp() */
- close(tmpfd);
+ vfs_stat(conn,fname,&sbuf);
- if (!fsp)
- {
- if((errno == ENOENT) && bad_path)
- {
- unix_ERR_class = ERRDOS;
- unix_ERR_code = ERRbadpath;
- }
- END_PROFILE(SMBctemp);
- return(UNIXERROR(ERRDOS,ERRnoaccess));
- }
+ /* Open file in dos compatibility share mode. */
+ /* We should fail if file does not exist. */
+ fsp = open_file_shared(conn,fname,&sbuf,
+ SET_DENY_MODE(DENY_FCB)|SET_OPEN_MODE(DOS_OPEN_FCB),
+ FILE_EXISTS_OPEN|FILE_FAIL_IF_NOT_EXIST,
+ unixmode, oplock_request, NULL, NULL);
+ /* close fd from smb_mkstemp() */
+ close(tmpfd);
- outsize = set_message(outbuf,1,0,True);
- SSVAL(outbuf,smb_vwv0,fsp->fnum);
+ if (!fsp) {
+ if((errno == ENOENT) && bad_path) {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
+ END_PROFILE(SMBctemp);
+ return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
- /* the returned filename is relative to the directory */
- s = strrchr_m(fname, '/');
- if (!s) {
- s = fname;
- } else {
- s++;
- }
+ /* the returned filename is relative to the directory */
+ s = strrchr(fname, '/');
+ if (!s)
+ s = fname;
+ else
+ s++;
- p = smb_buf(outbuf);
- SSVALS(p, 0, -1); /* what is this? not in spec */
- SSVAL(p, 2, strlen(s));
- p += 4;
- p += srvstr_push(outbuf, p, s, -1, STR_ASCII);
- outsize = set_message_end(outbuf, p);
+ outsize = set_message(outbuf,1,4+ strlen(fname),True);
+ SSVAL(outbuf,smb_vwv0,fsp->fnum);
- if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
- CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
- }
+ p = smb_buf(outbuf);
+ SSVALS(p, 0, -1); /* what is this? not in spec */
+ SSVAL(p, 2, strlen(s));
+ p += 4;
+ pstrcpy(p,s);
+
+ 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;
+ if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type))
+ CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
- DEBUG( 2, ( "created temp file %s\n", fname ) );
- DEBUG( 3, ( "ctemp %s fd=%d dmode=%d umode=%o\n",
- fname, fsp->fd, createmode, (int)unixmode ) );
+ DEBUG( 2, ( "created temp file %s\n", fname ) );
+ DEBUG( 3, ( "ctemp %s fd=%d dmode=%d umode=%o\n",
+ fname, fsp->fd, createmode, (int)unixmode ) );
- END_PROFILE(SMBctemp);
- return(outsize);
+ END_PROFILE(SMBctemp);
+ return(outsize);
}
/*******************************************************************
check if a user is allowed to delete a file
********************************************************************/
-static NTSTATUS can_delete(char *fname,connection_struct *conn, int dirtype)
+static BOOL can_delete(char *fname,connection_struct *conn, int dirtype)
{
- SMB_STRUCT_STAT sbuf;
- int fmode;
-
- if (!CAN_WRITE(conn)) return NT_STATUS_MEDIA_WRITE_PROTECTED;
-
- if (conn->vfs_ops.lstat(conn,fname,&sbuf) != 0) return NT_STATUS_OBJECT_NAME_NOT_FOUND;
-
- fmode = dos_mode(conn,fname,&sbuf);
- if (fmode & aDIR) return NT_STATUS_FILE_IS_A_DIRECTORY;
- if (!lp_delete_readonly(SNUM(conn))) {
- if (fmode & aRONLY) return NT_STATUS_CANNOT_DELETE;
- }
- if ((fmode & ~dirtype) & (aHIDDEN | aSYSTEM))
- return NT_STATUS_CANNOT_DELETE;
+ SMB_STRUCT_STAT sbuf;
+ int fmode;
- if (!check_file_sharing(conn,fname,False)) return NT_STATUS_SHARING_VIOLATION;
+ if (!CAN_WRITE(conn)) return(False);
- return NT_STATUS_OK;
+ if (conn->vfs_ops.lstat(conn,dos_to_unix(fname,False),&sbuf) != 0) return(False);
+ fmode = dos_mode(conn,fname,&sbuf);
+ if (fmode & aDIR) return(False);
+ if (!lp_delete_readonly(SNUM(conn))) {
+ if (fmode & aRONLY) return(False);
+ }
+ if ((fmode & ~dirtype) & (aHIDDEN | aSYSTEM))
+ return(False);
+ if (!check_file_sharing(conn,fname,False)) return(False);
+ return(True);
}
/****************************************************************************
@@ -1232,133 +1965,140 @@ static NTSTATUS can_delete(char *fname,connection_struct *conn, int dirtype)
code.
****************************************************************************/
-NTSTATUS unlink_internals(connection_struct *conn, int dirtype, char *name)
+int unlink_internals(connection_struct *conn, char *inbuf,char *outbuf,
+ int dirtype, char *name)
{
- pstring directory;
- pstring mask;
- char *p;
- int count=0;
- NTSTATUS error = NT_STATUS_OK;
- BOOL has_wild;
- BOOL exists=False;
- BOOL bad_path = False;
- BOOL rc = True;
- SMB_STRUCT_STAT sbuf;
-
- *directory = *mask = 0;
-
- rc = unix_convert(name,conn,0,&bad_path,&sbuf);
-
- p = strrchr_m(name,'/');
- if (!p) {
- pstrcpy(directory,"./");
- pstrcpy(mask,name);
- } else {
- *p = 0;
- pstrcpy(directory,name);
- pstrcpy(mask,p+1);
- }
-
- /*
- * 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) {
- pstrcat(directory,"/");
- pstrcat(directory,mask);
- error = can_delete(directory,conn,dirtype);
- if (!NT_STATUS_IS_OK(error)) return error;
+ pstring directory;
+ pstring mask;
+ char *p;
+ int count=0;
+ int error = ERRnoaccess;
+ BOOL has_wild;
+ BOOL exists=False;
+ BOOL bad_path = False;
+ BOOL rc = True;
+ SMB_STRUCT_STAT sbuf;
- if (vfs_unlink(conn,directory) == 0) {
- count++;
- }
- if (!count)
- exists = vfs_file_exist(conn,directory,&sbuf);
- } else {
- void *dirptr = NULL;
- char *dname;
-
- 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 = NT_STATUS_OBJECT_NAME_NOT_FOUND;
-
- if (strequal(mask,"????????.???"))
- pstrcpy(mask,"*");
+ *directory = *mask = 0;
- while ((dname = ReadDirName(dirptr))) {
- pstring fname;
- pstrcpy(fname,dname);
-
- if(!mask_match(fname, mask, case_sensitive)) continue;
-
- slprintf(fname,sizeof(fname)-1, "%s/%s",directory,dname);
- error = can_delete(fname,conn,dirtype);
- if (!NT_STATUS_IS_OK(error)) continue;
- if (vfs_unlink(conn,fname) == 0) count++;
- DEBUG(3,("unlink_internals: succesful unlink [%s]\n",fname));
- }
- CloseDir(dirptr);
- }
- }
-
- if (count == 0 && NT_STATUS_IS_OK(error)) {
- error = map_nt_error_from_unix(errno);
- }
+ rc = unix_convert(name,conn,0,&bad_path,&sbuf);
+
+ p = strrchr(name,'/');
+ if (!p) {
+ pstrcpy(directory,"./");
+ pstrcpy(mask,name);
+ } else {
+ *p = 0;
+ pstrcpy(directory,name);
+ pstrcpy(mask,p+1);
+ }
+
+ /*
+ * 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) {
+ pstrcat(directory,"/");
+ pstrcat(directory,mask);
+ if (can_delete(directory,conn,dirtype) && !vfs_unlink(conn,directory))
+ count++;
+ if (!count)
+ exists = vfs_file_exist(conn,directory,&sbuf);
+ } else {
+ void *dirptr = NULL;
+ char *dname;
+
+ 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;
- return error;
+ 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_delete(fname,conn,dirtype)) continue;
+ if (!vfs_unlink(conn,fname)) count++;
+ DEBUG(3,("unlink_internals: succesful unlink [%s]\n",fname));
+ }
+ CloseDir(dirptr);
+ }
+ }
+
+ if (count == 0) {
+ if (exists)
+ return(ERROR(ERRDOS,error));
+ else {
+ if((errno == ENOENT) && bad_path) {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
+ return(UNIXERROR(ERRDOS,error));
+ }
+ }
+
+ return 0;
}
/****************************************************************************
Reply to a unlink
****************************************************************************/
-int reply_unlink(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
- int dum_buffsize)
+int reply_unlink(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
{
- int outsize = 0;
- pstring name;
- int dirtype;
- NTSTATUS status;
- START_PROFILE(SMBunlink);
-
- dirtype = SVAL(inbuf,smb_vwv0);
-
- srvstr_pull(inbuf, name, smb_buf(inbuf) + 1, sizeof(name), -1, STR_TERMINATE);
-
- RESOLVE_DFSPATH(name, conn, inbuf, outbuf);
-
- DEBUG(3,("reply_unlink : %s\n",name));
-
- status = unlink_internals(conn, dirtype, name);
- if (!NT_STATUS_IS_OK(status)) return ERROR_NT(status);
+ int outsize = 0;
+ pstring name;
+ int dirtype;
+ START_PROFILE(SMBunlink);
- /*
- * Win2k needs a changenotify request response before it will
- * update after a rename..
- */
- process_pending_change_notify_queue((time_t)0);
-
- outsize = set_message(outbuf,0,0,True);
+ dirtype = SVAL(inbuf,smb_vwv0);
+
+ pstrcpy(name,smb_buf(inbuf) + 1);
+
+ RESOLVE_DFSPATH(name, conn, inbuf, outbuf);
+
+ DEBUG(3,("reply_unlink : %s\n",name));
+
+ outsize = unlink_internals(conn, inbuf, outbuf, dirtype, name);
+ if(outsize == 0) {
+
+ /*
+ * Win2k needs a changenotify request response before it will
+ * update after a rename..
+ */
+
+ process_pending_change_notify_queue((time_t)0);
+
+ outsize = set_message(outbuf,0,0,True);
+ }
- END_PROFILE(SMBunlink);
- return outsize;
+ END_PROFILE(SMBunlink);
+ return(outsize);
}
/****************************************************************************
@@ -1502,74 +2242,73 @@ int reply_readbraw(connection_struct *conn, char *inbuf, char *outbuf, int dum_s
return -1;
}
+
/****************************************************************************
reply to a lockread (core+ protocol)
****************************************************************************/
int reply_lockread(connection_struct *conn, char *inbuf,char *outbuf, int length, int dum_buffsiz)
{
- ssize_t nread = -1;
- char *data;
- int outsize = 0;
- SMB_OFF_T startpos;
- size_t numtoread;
- NTSTATUS status;
- files_struct *fsp = file_fsp(inbuf,smb_vwv0);
- START_PROFILE(SMBlockread);
+ ssize_t nread = -1;
+ char *data;
+ int outsize = 0;
+ SMB_OFF_T startpos;
+ size_t numtoread;
+ int eclass;
+ uint32 ecode;
+ files_struct *fsp = file_fsp(inbuf,smb_vwv0);
+ START_PROFILE(SMBlockread);
- CHECK_FSP(fsp,conn);
- CHECK_READ(fsp);
+ CHECK_FSP(fsp,conn);
+ CHECK_READ(fsp);
- release_level_2_oplocks_on_change(fsp);
+ release_level_2_oplocks_on_change(fsp);
- numtoread = SVAL(inbuf,smb_vwv1);
- startpos = IVAL(inbuf,smb_vwv2);
+ numtoread = SVAL(inbuf,smb_vwv1);
+ startpos = IVAL(inbuf,smb_vwv2);
- outsize = set_message(outbuf,5,3,True);
- numtoread = MIN(BUFFER_SIZE-outsize,numtoread);
- data = smb_buf(outbuf) + 3;
-
- /*
- * 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.
- */
-
- status = do_lock(fsp, conn, SVAL(inbuf,smb_pid),
- (SMB_BIG_UINT)numtoread, (SMB_BIG_UINT)startpos, WRITE_LOCK);
+ outsize = set_message(outbuf,5,3,True);
+ numtoread = MIN(BUFFER_SIZE-outsize,numtoread);
+ data = smb_buf(outbuf) + 3;
+
+ /*
+ * 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 (NT_STATUS_V(status)) {
- if (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))
- END_PROFILE(SMBlockread);
- return -1;
- }
+ if(!do_lock( fsp, conn, SVAL(inbuf,smb_pid), (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))
END_PROFILE(SMBlockread);
- return ERROR_NT(status);
- }
+ return -1;
+ }
+ END_PROFILE(SMBlockread);
+ return (ERROR(eclass,ecode));
+ }
- nread = read_file(fsp,data,startpos,numtoread);
+ nread = read_file(fsp,data,startpos,numtoread);
- if (nread < 0) {
- END_PROFILE(SMBlockread);
- 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,("lockread fnum=%d num=%d nread=%d\n",
- fsp->fnum, (int)numtoread, (int)nread));
+ if (nread < 0) {
+ END_PROFILE(SMBlockread);
+ return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
- END_PROFILE(SMBlockread);
- return(outsize);
+ outsize += nread;
+ SSVAL(outbuf,smb_vwv0,nread);
+ SSVAL(outbuf,smb_vwv5,nread+3);
+ SSVAL(smb_buf(outbuf),1,nread);
+
+ DEBUG( 3, ( "lockread fnum=%d num=%d nread=%d\n",
+ fsp->fnum, (int)numtoread, (int)nread ) );
+
+ END_PROFILE(SMBlockread);
+ return(outsize);
}
@@ -1592,20 +2331,19 @@ int reply_read(connection_struct *conn, char *inbuf,char *outbuf, int size, int
numtoread = SVAL(inbuf,smb_vwv1);
startpos = IVAL(inbuf,smb_vwv2);
-
-
+
outsize = set_message(outbuf,5,3,True);
numtoread = MIN(BUFFER_SIZE-outsize,numtoread);
data = smb_buf(outbuf) + 3;
if (is_locked(fsp,conn,(SMB_BIG_UINT)numtoread,(SMB_BIG_UINT)startpos, READ_LOCK,False)) {
END_PROFILE(SMBread);
- return ERROR_DOS(ERRDOS,ERRlock);
+ return(ERROR(ERRDOS,ERRlock));
}
if (numtoread > 0)
nread = read_file(fsp,data,startpos,numtoread);
-
+
if (nread < 0) {
END_PROFILE(SMBread);
return(UNIXERROR(ERRDOS,ERRnoaccess));
@@ -1667,7 +2405,7 @@ int reply_read_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
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) ));
END_PROFILE(SMBreadX);
- return ERROR_DOS(ERRDOS,ERRbadaccess);
+ return(ERROR(ERRDOS,ERRbadaccess));
}
#endif /* LARGE_SMB_OFF_T */
@@ -1676,10 +2414,10 @@ int reply_read_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
if (is_locked(fsp,conn,(SMB_BIG_UINT)smb_maxcnt,(SMB_BIG_UINT)startpos, READ_LOCK,False)) {
END_PROFILE(SMBreadX);
- return ERROR_DOS(ERRDOS,ERRlock);
+ return(ERROR(ERRDOS,ERRlock));
}
nread = read_file(fsp,data,startpos,smb_maxcnt);
-
+
if (nread < 0) {
END_PROFILE(SMBreadX);
return(UNIXERROR(ERRDOS,ERRnoaccess));
@@ -1737,7 +2475,7 @@ int reply_writebraw(connection_struct *conn, char *inbuf,char *outbuf, int size,
if (is_locked(fsp,conn,(SMB_BIG_UINT)tcount,(SMB_BIG_UINT)startpos, WRITE_LOCK,False)) {
END_PROFILE(SMBwritebraw);
- return(ERROR_DOS(ERRDOS,ERRlock));
+ return(ERROR(ERRDOS,ERRlock));
}
if (numtowrite>0)
@@ -1828,65 +2566,83 @@ int reply_writebraw(connection_struct *conn, char *inbuf,char *outbuf, int size,
reply to a writeunlock (core+)
****************************************************************************/
-int reply_writeunlock(connection_struct *conn, char *inbuf,char *outbuf,
- int size, int dum_buffsize)
+int reply_writeunlock(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
{
- ssize_t nwritten = -1;
- size_t numtowrite;
- SMB_OFF_T startpos;
- char *data;
- NTSTATUS status;
- files_struct *fsp = file_fsp(inbuf,smb_vwv0);
- int outsize = 0;
- START_PROFILE(SMBwriteunlock);
-
- CHECK_FSP(fsp,conn);
- CHECK_WRITE(fsp);
+ ssize_t nwritten = -1;
+ size_t numtowrite;
+ SMB_OFF_T startpos;
+ char *data;
+ int eclass;
+ uint32 ecode;
+ files_struct *fsp = file_fsp(inbuf,smb_vwv0);
+ int outsize = 0;
+ START_PROFILE(SMBwriteunlock);
- numtowrite = SVAL(inbuf,smb_vwv1);
- startpos = IVAL(inbuf,smb_vwv2);
- data = smb_buf(inbuf) + 3;
+ CHECK_FSP(fsp,conn);
+ CHECK_WRITE(fsp);
+
+ numtowrite = SVAL(inbuf,smb_vwv1);
+ startpos = IVAL(inbuf,smb_vwv2);
+ data = smb_buf(inbuf) + 3;
- if (is_locked(fsp,conn,(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos,
- WRITE_LOCK,False)) {
- END_PROFILE(SMBwriteunlock);
- return ERROR_DOS(ERRDOS,ERRlock);
- }
+ if (is_locked(fsp,conn,(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, WRITE_LOCK,False)) {
+ END_PROFILE(SMBwriteunlock);
+ return(ERROR(ERRDOS,ERRlock));
+ }
- /* 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(fsp,data,startpos,numtowrite);
+ /* 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(fsp,data,startpos,numtowrite);
- if (lp_syncalways(SNUM(conn)))
- sync_file(conn,fsp);
+ if (lp_syncalways(SNUM(conn)))
+ sync_file(conn,fsp);
- if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
- END_PROFILE(SMBwriteunlock);
- return(UNIXERROR(ERRDOS,ERRnoaccess));
- }
+ if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
+ END_PROFILE(SMBwriteunlock);
+ return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
- status = do_unlock(fsp, conn, SVAL(inbuf,smb_pid), (SMB_BIG_UINT)numtowrite,
- (SMB_BIG_UINT)startpos);
- if (NT_STATUS_V(status)) {
- END_PROFILE(SMBwriteunlock);
- return ERROR_NT(status);
- }
-
- outsize = set_message(outbuf,1,0,True);
-
- SSVAL(outbuf,smb_vwv0,nwritten);
-
- DEBUG(3,("writeunlock fnum=%d num=%d wrote=%d\n",
- fsp->fnum, (int)numtowrite, (int)nwritten));
-
- END_PROFILE(SMBwriteunlock);
- return outsize;
+ if(!do_unlock(fsp, conn, SVAL(inbuf,smb_pid), (SMB_BIG_UINT)numtowrite, (SMB_BIG_UINT)startpos, &eclass, &ecode)) {
+ END_PROFILE(SMBwriteunlock);
+ return(ERROR(eclass,ecode));
+ }
+
+ outsize = set_message(outbuf,1,0,True);
+
+ SSVAL(outbuf,smb_vwv0,nwritten);
+
+ DEBUG( 3, ( "writeunlock fnum=%d num=%d wrote=%d\n",
+ fsp->fnum, (int)numtowrite, (int)nwritten ) );
+
+ END_PROFILE(SMBwriteunlock);
+ return(outsize);
}
+/****************************************************************************
+ Return correct error for space allocation fail.
+****************************************************************************/
+
+int allocate_space_error(char *inbuf,char *outbuf, int errno_val)
+{
+ errno = errno_val;
+ if (!(global_client_caps & CAP_STATUS32))
+ return (UNIXERROR(ERRHRD,ERRdiskfull));
+
+ /* Use more specific WNT/W2K error codes. */
+#ifdef EDQUOT
+ if (errno_val == ENOSPC || errno_val == EDQUOT) {
+#else
+ if (errno_val == ENOSPC) {
+#endif
+ return(ERROR(0,NT_STATUS_DISK_FULL));
+ }
+
+ return (UNIXERROR(ERRHRD,ERRdiskfull));
+}
/****************************************************************************
Reply to a write.
@@ -1917,7 +2673,7 @@ int reply_write(connection_struct *conn, char *inbuf,char *outbuf,int size,int d
if (is_locked(fsp,conn,(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, WRITE_LOCK,False)) {
END_PROFILE(SMBwrite);
- return ERROR_DOS(ERRDOS,ERRlock);
+ return(ERROR(ERRDOS,ERRlock));
}
/* X/Open SMB protocol says that if smb_vwv1 is
@@ -1927,8 +2683,9 @@ int reply_write(connection_struct *conn, char *inbuf,char *outbuf,int size,int d
/* This is actually an allocate call, not set EOF. JRA */
nwritten = vfs_allocate_file_space(fsp, (SMB_OFF_T)startpos);
if (nwritten < 0) {
- END_PROFILE(SMBwrite);
- return ERROR_NT(NT_STATUS_DISK_FULL);
+ int ret = allocate_space_error(inbuf, outbuf, errno);
+ END_PROFILE(SMBwrite);
+ return ret;
}
} else
nwritten = write_file(fsp,data,startpos,numtowrite);
@@ -1989,7 +2746,7 @@ int reply_write_and_X(connection_struct *conn, char *inbuf,char *outbuf,int leng
if(smb_doff > smblen || (smb_doff + numtowrite > smblen)) {
END_PROFILE(SMBwriteX);
- return ERROR_DOS(ERRDOS,ERRbadmem);
+ return(ERROR(ERRDOS,ERRbadmem));
}
data = smb_base(inbuf) + smb_doff;
@@ -2011,7 +2768,7 @@ int reply_write_and_X(connection_struct *conn, char *inbuf,char *outbuf,int leng
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) ));
END_PROFILE(SMBwriteX);
- return ERROR_DOS(ERRDOS,ERRbadaccess);
+ return(ERROR(ERRDOS,ERRbadaccess));
}
#endif /* LARGE_SMB_OFF_T */
@@ -2019,7 +2776,7 @@ int reply_write_and_X(connection_struct *conn, char *inbuf,char *outbuf,int leng
if (is_locked(fsp,conn,(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, WRITE_LOCK,False)) {
END_PROFILE(SMBwriteX);
- return ERROR_DOS(ERRDOS,ERRlock);
+ return(ERROR(ERRDOS,ERRlock));
}
/* X/Open SMB protocol says that, unlike SMBwrite
@@ -2140,7 +2897,7 @@ int reply_lseek(connection_struct *conn, char *inbuf,char *outbuf, int size, int
}
/****************************************************************************
- reply to a flush
+ Reply to a flush.
****************************************************************************/
int reply_flush(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
@@ -2150,19 +2907,18 @@ int reply_flush(connection_struct *conn, char *inbuf,char *outbuf, int size, int
START_PROFILE(SMBflush);
CHECK_FSP(fsp,conn);
-
+
if (!fsp) {
file_sync_all(conn);
} else {
sync_file(conn,fsp);
}
-
+
DEBUG(3,("flush\n"));
END_PROFILE(SMBflush);
return(outsize);
}
-
/****************************************************************************
reply to a exit
****************************************************************************/
@@ -2188,7 +2944,6 @@ int reply_close(connection_struct *conn, char *inbuf,char *outbuf, int size,
{
int outsize = 0;
time_t mtime;
- int32 eclass = 0, err = 0;
files_struct *fsp = NULL;
START_PROFILE(SMBclose);
@@ -2208,7 +2963,7 @@ int reply_close(connection_struct *conn, char *inbuf,char *outbuf, int size,
if(!fsp || (fsp->conn != conn)) {
END_PROFILE(SMBclose);
- return ERROR_DOS(ERRDOS,ERRbadfid);
+ return(ERROR(ERRDOS,ERRbadfid));
}
if(fsp->is_directory || fsp->stat_open) {
@@ -2256,12 +3011,6 @@ int reply_close(connection_struct *conn, char *inbuf,char *outbuf, int size,
}
}
- /* We have a cached error */
- if(eclass || err) {
- END_PROFILE(SMBclose);
- return ERROR_DOS(eclass,err);
- }
-
END_PROFILE(SMBclose);
return(outsize);
}
@@ -2294,7 +3043,7 @@ int reply_writeclose(connection_struct *conn,
if (is_locked(fsp,conn,(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, WRITE_LOCK,False)) {
END_PROFILE(SMBwriteclose);
- return ERROR_DOS(ERRDOS,ERRlock);
+ return(ERROR(ERRDOS,ERRlock));
}
nwritten = write_file(fsp,data,startpos,numtowrite);
@@ -2334,7 +3083,8 @@ int reply_lock(connection_struct *conn,
{
int outsize = set_message(outbuf,0,0,True);
SMB_BIG_UINT count,offset;
- NTSTATUS status;
+ int eclass;
+ uint32 ecode;
files_struct *fsp = file_fsp(inbuf,smb_vwv0);
START_PROFILE(SMBlock);
@@ -2348,21 +3098,20 @@ int reply_lock(connection_struct *conn,
DEBUG(3,("lock fd=%d fnum=%d offset=%.0f count=%.0f\n",
fsp->fd, fsp->fnum, (double)offset, (double)count));
- status = do_lock(fsp, conn, SVAL(inbuf,smb_pid), count, offset, WRITE_LOCK);
- if (NT_STATUS_V(status)) {
- if (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)) {
- END_PROFILE(SMBlock);
- return -1;
- }
- }
- END_PROFILE(SMBlock);
- return ERROR_NT(status);
+ if (!do_lock(fsp, conn, SVAL(inbuf,smb_pid), 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)) {
+ END_PROFILE(SMBlock);
+ return -1;
+ }
+ }
+ END_PROFILE(SMBlock);
+ return (ERROR(eclass,ecode));
}
END_PROFILE(SMBlock);
@@ -2373,31 +3122,30 @@ int reply_lock(connection_struct *conn,
/****************************************************************************
reply to a unlock
****************************************************************************/
-int reply_unlock(connection_struct *conn, char *inbuf,char *outbuf, int size,
- int dum_buffsize)
+int reply_unlock(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
{
- int outsize = set_message(outbuf,0,0,True);
- SMB_BIG_UINT count,offset;
- NTSTATUS status;
- files_struct *fsp = file_fsp(inbuf,smb_vwv0);
- START_PROFILE(SMBunlock);
+ 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);
+ START_PROFILE(SMBunlock);
- CHECK_FSP(fsp,conn);
-
- count = (SMB_BIG_UINT)IVAL(inbuf,smb_vwv1);
- offset = (SMB_BIG_UINT)IVAL(inbuf,smb_vwv3);
-
- status = do_unlock(fsp, conn, SVAL(inbuf,smb_pid), count, offset);
- if (NT_STATUS_V(status)) {
- END_PROFILE(SMBunlock);
- return ERROR_NT(status);
- }
+ CHECK_FSP(fsp,conn);
- DEBUG( 3, ( "unlock fd=%d fnum=%d offset=%.0f count=%.0f\n",
- fsp->fd, fsp->fnum, (double)offset, (double)count ) );
-
- END_PROFILE(SMBunlock);
- return(outsize);
+ count = (SMB_BIG_UINT)IVAL(inbuf,smb_vwv1);
+ offset = (SMB_BIG_UINT)IVAL(inbuf,smb_vwv3);
+
+ if(!do_unlock(fsp, conn, SVAL(inbuf,smb_pid), count, offset, &eclass, &ecode)) {
+ END_PROFILE(SMBunlock);
+ return (ERROR(eclass,ecode));
+ }
+
+ DEBUG( 3, ( "unlock fd=%d fnum=%d offset=%.0f count=%.0f\n",
+ fsp->fd, fsp->fnum, (double)offset, (double)count ) );
+
+ END_PROFILE(SMBunlock);
+ return(outsize);
}
@@ -2416,7 +3164,7 @@ int reply_tdis(connection_struct *conn,
if (!conn) {
DEBUG(4,("Invalid connection in tdis\n"));
END_PROFILE(SMBtdis);
- return ERROR_DOS(ERRSRV,ERRinvnid);
+ return(ERROR(ERRSRV,ERRinvnid));
}
conn->used = False;
@@ -2482,7 +3230,7 @@ int reply_printopen(connection_struct *conn,
if (!CAN_PRINT(conn)) {
END_PROFILE(SMBsplopen);
- return ERROR_DOS(ERRDOS,ERRnoaccess);
+ return(ERROR(ERRDOS,ERRnoaccess));
}
/* Open for exclusive use, write only. */
@@ -2519,7 +3267,7 @@ int reply_printclose(connection_struct *conn,
if (!CAN_PRINT(conn)) {
END_PROFILE(SMBsplclose);
- return ERROR_DOS(ERRDOS,ERRnoaccess);
+ return(ERROR(ERRDOS,ERRnoaccess));
}
DEBUG(3,("printclose fd=%d fnum=%d\n",
@@ -2555,7 +3303,7 @@ int reply_printqueue(connection_struct *conn,
get it right (tridge) */
if (!CAN_PRINT(conn)) {
END_PROFILE(SMBsplretq);
- return ERROR_DOS(ERRDOS,ERRnoaccess);
+ return(ERROR(ERRDOS,ERRnoaccess));
}
SSVAL(outbuf,smb_vwv0,0);
@@ -2586,7 +3334,7 @@ int reply_printqueue(connection_struct *conn,
SSVAL(p,5, queue[i].job);
SIVAL(p,7,queue[i].size);
CVAL(p,11) = 0;
- srvstr_push(outbuf, p+12, queue[i].user, 16, STR_ASCII);
+ StrnCpy(p+12,queue[i].user,16);
p += 28;
}
@@ -2598,7 +3346,7 @@ int reply_printqueue(connection_struct *conn,
SSVAL(smb_buf(outbuf),1,28*count);
}
- SAFE_FREE(queue);
+ if (queue) free(queue);
DEBUG(3,("%d entries returned in queue\n",count));
}
@@ -2621,7 +3369,7 @@ int reply_printwrite(connection_struct *conn, char *inbuf,char *outbuf, int dum_
if (!CAN_PRINT(conn)) {
END_PROFILE(SMBsplwr);
- return ERROR_DOS(ERRDOS,ERRnoaccess);
+ return(ERROR(ERRDOS,ERRnoaccess));
}
CHECK_FSP(fsp,conn);
@@ -2646,41 +3394,45 @@ int reply_printwrite(connection_struct *conn, char *inbuf,char *outbuf, int dum_
The guts of the mkdir command, split out so it may be called by the NT SMB
code.
****************************************************************************/
-NTSTATUS mkdir_internal(connection_struct *conn, pstring directory)
+int mkdir_internal(connection_struct *conn, char *inbuf, char *outbuf, pstring directory)
{
- BOOL bad_path = False;
- SMB_STRUCT_STAT sbuf;
- int ret= -1;
-
- unix_convert(directory,conn,0,&bad_path,&sbuf);
-
- if (check_name(directory, conn))
- ret = vfs_mkdir(conn,directory,unix_mode(conn,aDIR,directory));
-
- if (ret == -1) {
- return map_nt_error_from_unix(errno);
- }
-
- return NT_STATUS_OK;
+ BOOL bad_path = False;
+ SMB_STRUCT_STAT sbuf;
+ int ret= -1;
+
+ unix_convert(directory,conn,0,&bad_path,&sbuf);
+
+ if (check_name(directory, conn))
+ ret = vfs_mkdir(conn,directory,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));
+ }
+
+ return ret;
}
/****************************************************************************
- Reply to a mkdir.
+ Reply to a mkdir
****************************************************************************/
int reply_mkdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
{
pstring directory;
int outsize;
- NTSTATUS status;
START_PROFILE(SMBmkdir);
- srvstr_pull(inbuf, directory, smb_buf(inbuf) + 1, sizeof(directory), -1, STR_TERMINATE);
+ pstrcpy(directory,smb_buf(inbuf) + 1);
- status = mkdir_internal(conn, directory);
- if (!NT_STATUS_IS_OK(status)) return ERROR_NT(status);
-
- outsize = set_message(outbuf,0,0,True);
+ 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 ) );
@@ -2720,7 +3472,7 @@ static BOOL recursive_rmdir(connection_struct *conn, char *directory)
pstrcat(fullname, "/");
pstrcat(fullname, dname);
- if(conn->vfs_ops.lstat(conn,fullname, &st) != 0) {
+ if(conn->vfs_ops.lstat(conn,dos_to_unix(fullname,False), &st) != 0) {
ret = True;
break;
}
@@ -2739,6 +3491,7 @@ static BOOL recursive_rmdir(connection_struct *conn, char *directory)
break;
}
}
+
CloseDir(dirptr);
return ret;
}
@@ -2773,7 +3526,6 @@ BOOL rmdir_internals(connection_struct *conn, char *directory)
break;
}
}
-
if(all_veto_files) {
SeekDir(dirptr,dirpos);
while ((dname = ReadDirName(dirptr))) {
@@ -2788,12 +3540,11 @@ BOOL rmdir_internals(connection_struct *conn, char *directory)
errno = ENOMEM;
break;
}
-
pstrcpy(fullname, directory);
pstrcat(fullname, "/");
pstrcat(fullname, dname);
- if(conn->vfs_ops.lstat(conn,fullname, &st) != 0)
+ if(conn->vfs_ops.lstat(conn,dos_to_unix(fullname, False), &st) != 0)
break;
if(st.st_mode & S_IFDIR) {
if(lp_recursive_veto_delete(SNUM(conn))) {
@@ -2815,7 +3566,7 @@ BOOL rmdir_internals(connection_struct *conn, char *directory)
errno = ENOTEMPTY;
}
}
-
+
if (!ok)
DEBUG(3,("rmdir_internals: couldn't remove directory %s : %s\n", directory,strerror(errno)));
@@ -2835,7 +3586,7 @@ int reply_rmdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
SMB_STRUCT_STAT sbuf;
START_PROFILE(SMBrmdir);
- srvstr_pull(inbuf, directory, smb_buf(inbuf) + 1, sizeof(directory), -1, STR_TERMINATE);
+ pstrcpy(directory,smb_buf(inbuf) + 1);
RESOLVE_DFSPATH(directory, conn, inbuf, outbuf)
@@ -2876,21 +3627,21 @@ static BOOL resolve_wildcards(char *name1,char *name2)
fstring ext1,ext2;
char *p,*p2;
- name1 = strrchr_m(name1,'/');
- name2 = strrchr_m(name2,'/');
+ name1 = strrchr(name1,'/');
+ name2 = strrchr(name2,'/');
if (!name1 || !name2) return(False);
fstrcpy(root1,name1);
fstrcpy(root2,name2);
- p = strrchr_m(root1,'.');
+ p = strrchr(root1,'.');
if (p) {
*p = 0;
fstrcpy(ext1,p+1);
} else {
fstrcpy(ext1,"");
}
- p = strrchr_m(root2,'.');
+ p = strrchr(root2,'.');
if (p) {
*p = 0;
fstrcpy(ext2,p+1);
@@ -2940,7 +3691,7 @@ static BOOL can_rename(char *fname,connection_struct *conn)
if (!CAN_WRITE(conn)) return(False);
- if (conn->vfs_ops.lstat(conn,fname,&sbuf) != 0) return(False);
+ if (conn->vfs_ops.lstat(conn,dos_to_unix(fname,False),&sbuf) != 0) return(False);
if (!check_file_sharing(conn,fname,True)) return(False);
return(True);
}
@@ -2949,9 +3700,9 @@ static BOOL can_rename(char *fname,connection_struct *conn)
The guts of the rename command, split out so it may be called by the NT SMB
code.
****************************************************************************/
-NTSTATUS rename_internals(connection_struct *conn,
- char *name,
- char *newname, BOOL replace_if_exists)
+int rename_internals(connection_struct *conn,
+ char *inbuf, char *outbuf, char *name,
+ char *newname, BOOL replace_if_exists)
{
pstring directory;
pstring mask;
@@ -2961,10 +3712,11 @@ NTSTATUS rename_internals(connection_struct *conn,
BOOL bad_path1 = False;
BOOL bad_path2 = False;
int count=0;
- NTSTATUS error = NT_STATUS_OK;
+ int error = ERRnoaccess;
BOOL exists=False;
BOOL rc = True;
SMB_STRUCT_STAT sbuf1, sbuf2;
+ pstring zdirectory;
*directory = *mask = 0;
@@ -2980,7 +3732,7 @@ NTSTATUS rename_internals(connection_struct *conn,
* as this is checked in resolve_wildcards().
*/
- p = strrchr_m(name,'/');
+ p = strrchr(name,'/');
if (!p) {
pstrcpy(directory,".");
pstrcpy(mask,name);
@@ -3016,7 +3768,7 @@ NTSTATUS rename_internals(connection_struct *conn,
pstrcat(directory,mask);
/* Ensure newname contains a '/' also */
- if(strrchr_m(newname,'/') == 0) {
+ if(strrchr(newname,'/') == 0) {
pstring tmpstr;
pstrcpy(tmpstr, "./");
@@ -3049,7 +3801,7 @@ NTSTATUS rename_internals(connection_struct *conn,
* Note that we guarantee that newname contains a '/'
* character above.
*/
- p = strrchr_m(newname,'/');
+ p = strrchr(newname,'/');
pstrcpy(newname_modified_last_component,p+1);
if(strcsequal(newname_modified_last_component,
@@ -3062,6 +3814,7 @@ NTSTATUS rename_internals(connection_struct *conn,
}
}
+ pstrcpy(zdirectory, dos_to_unix(directory, False));
if(replace_if_exists) {
/*
* NT SMB specific flag - rename can overwrite
@@ -3071,13 +3824,15 @@ NTSTATUS rename_internals(connection_struct *conn,
if(resolve_wildcards(directory,newname) &&
can_rename(directory,conn) &&
- conn->vfs_ops.rename(conn,directory,newname) == 0)
+ !conn->vfs_ops.rename(conn,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(conn,directory,newname) == 0)
+ !conn->vfs_ops.rename(conn,zdirectory,
+ dos_to_unix(newname,False)))
count++;
}
@@ -3087,7 +3842,7 @@ NTSTATUS rename_internals(connection_struct *conn,
if (!count) exists = vfs_file_exist(conn,directory,NULL);
if (!count && exists && vfs_file_exist(conn,newname,NULL)) {
exists = True;
- error = NT_STATUS_OBJECT_NAME_COLLISION;
+ error = ERRrename;
}
} else {
/*
@@ -3101,7 +3856,7 @@ NTSTATUS rename_internals(connection_struct *conn,
dirptr = OpenDir(conn, directory, True);
if (dirptr) {
- error = NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ error = ERRbadfile;
if (strequal(mask,"????????.???"))
pstrcpy(mask,"*");
@@ -3114,7 +3869,7 @@ NTSTATUS rename_internals(connection_struct *conn,
if(!mask_match(fname, mask, case_sensitive))
continue;
- error = NT_STATUS_ACCESS_DENIED;
+ error = ERRnoaccess;
slprintf(fname,sizeof(fname)-1,"%s/%s",directory,dname);
if (!can_rename(fname,conn)) {
DEBUG(6,("rename %s refused\n", fname));
@@ -3131,11 +3886,12 @@ NTSTATUS rename_internals(connection_struct *conn,
if (!replace_if_exists &&
vfs_file_exist(conn,destname, NULL)) {
DEBUG(6,("file_exist %s\n", destname));
- error = NT_STATUS_OBJECT_NAME_COLLISION;
+ error = 183;
continue;
}
- if (!conn->vfs_ops.rename(conn,fname,destname))
+ if (!conn->vfs_ops.rename(conn,dos_to_unix(fname,False),
+ dos_to_unix(destname,False)))
count++;
DEBUG(3,("rename_internals: doing rename on %s -> %s\n",fname,destname));
}
@@ -3143,52 +3899,55 @@ NTSTATUS rename_internals(connection_struct *conn,
}
}
- if (count == 0 && NT_STATUS_IS_OK(error)) {
- error = map_nt_error_from_unix(errno);
+ 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 error;
+ return 0;
}
/****************************************************************************
Reply to a mv.
****************************************************************************/
-int reply_mv(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
- int dum_buffsize)
+int reply_mv(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
{
- int outsize = 0;
- pstring name;
- pstring newname;
- char *p;
- NTSTATUS status;
+ int outsize = 0;
+ pstring name;
+ pstring newname;
+ START_PROFILE(SMBmv);
- START_PROFILE(SMBmv);
+ pstrcpy(name,smb_buf(inbuf) + 1);
+ pstrcpy(newname,smb_buf(inbuf) + 3 + strlen(name));
- p = smb_buf(inbuf) + 1;
- p += srvstr_pull(inbuf, name, p, sizeof(name), -1, STR_TERMINATE);
- p++;
- p += srvstr_pull(inbuf, newname, p, sizeof(newname), -1, STR_TERMINATE);
-
- RESOLVE_DFSPATH(name, conn, inbuf, outbuf);
- RESOLVE_DFSPATH(newname, conn, inbuf, outbuf);
-
- DEBUG(3,("reply_mv : %s -> %s\n",name,newname));
-
- status = rename_internals(conn, name, newname, False);
- if (!NT_STATUS_IS_OK(status)) {
- return ERROR_NT(status);
- }
+ RESOLVE_DFSPATH(name, conn, inbuf, outbuf);
+ RESOLVE_DFSPATH(newname, conn, inbuf, outbuf);
+
+ DEBUG(3,("reply_mv : %s -> %s\n",name,newname));
+
+ outsize = rename_internals(conn, inbuf, outbuf, name, newname, False);
+ if(outsize == 0) {
/*
- * Win2k needs a changenotify request response before it will
- * update after a rename..
- */
- process_pending_change_notify_queue((time_t)0);
- outsize = set_message(outbuf,0,0,True);
+ * Win2k needs a changenotify request response before it will
+ * update after a rename..
+ */
+
+ process_pending_change_notify_queue((time_t)0);
+
+ outsize = set_message(outbuf,0,0,True);
+ }
- END_PROFILE(SMBmv);
- return(outsize);
+ END_PROFILE(SMBmv);
+ return(outsize);
}
/*******************************************************************
@@ -3208,7 +3967,7 @@ static BOOL copy_file(char *src,char *dest1,connection_struct *conn, int ofun,
pstrcpy(dest,dest1);
if (target_is_directory) {
- char *p = strrchr_m(src,'/');
+ char *p = strrchr(src,'/');
if (p)
p++;
else
@@ -3266,6 +4025,8 @@ static BOOL copy_file(char *src,char *dest1,connection_struct *conn, int ofun,
return(ret == (SMB_OFF_T)src_sbuf.st_size);
}
+
+
/****************************************************************************
reply to a file copy.
****************************************************************************/
@@ -3293,9 +4054,8 @@ int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
*directory = *mask = 0;
- p = smb_buf(inbuf);
- p += srvstr_pull(inbuf, name, p, sizeof(name), -1, STR_TERMINATE);
- p += srvstr_pull(inbuf, newname, p, sizeof(newname), -1, STR_TERMINATE);
+ pstrcpy(name,smb_buf(inbuf));
+ pstrcpy(newname,smb_buf(inbuf) + 1 + strlen(name));
DEBUG(3,("reply_copy : %s -> %s\n",name,newname));
@@ -3303,7 +4063,7 @@ int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
/* can't currently handle inter share copies XXXX */
DEBUG(3,("Rejecting inter-share copy\n"));
END_PROFILE(SMBcopy);
- return ERROR_DOS(ERRSRV,ERRinvdevice);
+ return(ERROR(ERRSRV,ERRinvdevice));
}
RESOLVE_DFSPATH(name, conn, inbuf, outbuf);
@@ -3316,22 +4076,22 @@ int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
if ((flags&1) && target_is_directory) {
END_PROFILE(SMBcopy);
- return ERROR_DOS(ERRDOS,ERRbadfile);
+ return(ERROR(ERRDOS,ERRbadfile));
}
if ((flags&2) && !target_is_directory) {
END_PROFILE(SMBcopy);
- return ERROR_DOS(ERRDOS,ERRbadpath);
+ return(ERROR(ERRDOS,ERRbadpath));
}
if ((flags&(1<<5)) && VALID_STAT_OF_DIR(sbuf1)) {
/* wants a tree copy! XXXX */
DEBUG(3,("Rejecting tree copy\n"));
END_PROFILE(SMBcopy);
- return ERROR_DOS(ERRSRV,ERRerror);
+ return(ERROR(ERRSRV,ERRerror));
}
- p = strrchr_m(name,'/');
+ p = strrchr(name,'/');
if (!p) {
pstrcpy(directory,"./");
pstrcpy(mask,name);
@@ -3410,7 +4170,7 @@ int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
if (exists) {
END_PROFILE(SMBcopy);
- return ERROR_DOS(ERRDOS,error);
+ return(ERROR(ERRDOS,error));
} else
{
if((errno == ENOENT) && (bad_path1 || bad_path2))
@@ -3444,10 +4204,11 @@ int reply_setdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
snum = SNUM(conn);
if (!CAN_SETDIR(snum)) {
END_PROFILE(pathworks_setdir);
- return ERROR_DOS(ERRDOS,ERRnoaccess);
+ return(ERROR(ERRDOS,ERRnoaccess));
}
-
- srvstr_pull(inbuf, newdir, smb_buf(inbuf) + 1, sizeof(newdir), -1, STR_TERMINATE);
+
+ pstrcpy(newdir,smb_buf(inbuf) + 1);
+ strlower(newdir);
if (strlen(newdir) == 0) {
ok = True;
@@ -3460,7 +4221,7 @@ int reply_setdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
if (!ok) {
END_PROFILE(pathworks_setdir);
- return ERROR_DOS(ERRDOS,ERRbadpath);
+ return(ERROR(ERRDOS,ERRbadpath));
}
outsize = set_message(outbuf,0,0,True);
@@ -3526,6 +4287,7 @@ SMB_BIG_UINT get_lock_count( char *data, int data_offset, BOOL large_file_format
/****************************************************************************
Pathetically try and map a 64 bit lock offset into 31 bits. I hate Windows :-).
****************************************************************************/
+
static uint32 map_lock_offset(uint32 high, uint32 low)
{
unsigned int i;
@@ -3610,184 +4372,187 @@ SMB_BIG_UINT get_lock_offset( char *data, int data_offset, BOOL large_file_forma
int reply_lockingX(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
{
- files_struct *fsp = file_fsp(inbuf,smb_vwv2);
- unsigned char locktype = CVAL(inbuf,smb_vwv3);
- unsigned char oplocklevel = CVAL(inbuf,smb_vwv3+1);
- uint16 num_ulocks = SVAL(inbuf,smb_vwv6);
- uint16 num_locks = SVAL(inbuf,smb_vwv7);
- SMB_BIG_UINT count = 0, offset = 0;
- uint16 lock_pid;
- int32 lock_timeout = IVAL(inbuf,smb_vwv4);
- int i;
- char *data;
- BOOL large_file_format = (locktype & LOCKING_ANDX_LARGE_FILES)?True:False;
- BOOL err;
- NTSTATUS status;
+ files_struct *fsp = file_fsp(inbuf,smb_vwv2);
+ unsigned char locktype = CVAL(inbuf,smb_vwv3);
+ unsigned char oplocklevel = CVAL(inbuf,smb_vwv3+1);
+ uint16 num_ulocks = SVAL(inbuf,smb_vwv6);
+ uint16 num_locks = SVAL(inbuf,smb_vwv7);
+ SMB_BIG_UINT count = 0, offset = 0;
+ uint16 lock_pid;
+ int32 lock_timeout = IVAL(inbuf,smb_vwv4);
+ int i;
+ char *data;
+ uint32 ecode=0, dummy2;
+ int eclass=0, dummy1;
+ BOOL large_file_format = (locktype & LOCKING_ANDX_LARGE_FILES)?True:False;
+ BOOL err;
+ START_PROFILE(SMBlockingX);
- START_PROFILE(SMBlockingX);
-
- CHECK_FSP(fsp,conn);
-
- 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)) {
- /* Client can insist on breaking to none. */
- BOOL break_to_none = (oplocklevel == 0);
-
- DEBUG(5,("reply_lockingX: oplock break reply (%u) from client for fnum = %d\n",
- (unsigned int)oplocklevel, fsp->fnum ));
+ CHECK_FSP(fsp,conn);
- /*
- * 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 \
+ 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))
+ {
+ /* Client can insist on breaking to none. */
+ BOOL break_to_none = (oplocklevel == 0);
+
+ DEBUG(5,("reply_lockingX: oplock break reply (%u) from client for fnum = %d\n",
+ (unsigned int)oplocklevel, 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) {
- END_PROFILE(SMBlockingX);
- return -1;
- } else {
- END_PROFILE(SMBlockingX);
- return ERROR_DOS(ERRDOS,ERRlock);
- }
- }
+ /* if this is a pure oplock break request then don't send a reply */
+ if (num_locks == 0 && num_ulocks == 0) {
+ END_PROFILE(SMBlockingX);
+ return -1;
+ } else {
+ END_PROFILE(SMBlockingX);
+ return ERROR(ERRDOS,ERRlock);
+ }
+ }
- if (remove_oplock(fsp, break_to_none) == 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) ));
- END_PROFILE(SMBlockingX);
- return -1;
- }
- }
+ if (remove_oplock(fsp, break_to_none) == False) {
+ DEBUG(0,("reply_lockingX: error in removing oplock on file %s\n",
+ fsp->fsp_name ));
+ }
- /*
- * We do this check *after* we have checked this is not a oplock break
- * response message. JRA.
- */
-
- release_level_2_oplocks_on_change(fsp);
-
- /* Data now points at the beginning of the list
- of smb_unlkrng structs */
- for(i = 0; i < (int)num_ulocks; i++) {
- lock_pid = get_lock_pid( data, i, large_file_format);
- 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) {
- END_PROFILE(SMBlockingX);
- return ERROR_DOS(ERRDOS,ERRnoaccess);
- }
+ /* 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) ));
+ END_PROFILE(SMBlockingX);
+ return -1;
+ }
+ }
- DEBUG(10,("reply_lockingX: unlock start=%.0f, len=%.0f for pid %u, file %s\n",
- (double)offset, (double)count, (unsigned int)lock_pid, fsp->fsp_name ));
-
- status = do_unlock(fsp,conn,lock_pid,count,offset);
- if (NT_STATUS_V(status)) {
- END_PROFILE(SMBlockingX);
- return ERROR_NT(status);
- }
- }
+ /*
+ * We do this check *after* we have checked this is not a oplock break
+ * response message. JRA.
+ */
- /* Setup the timeout in seconds. */
- lock_timeout = ((lock_timeout == -1) ? -1 : lock_timeout/1000);
-
- /* Now do any requested locks */
- 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++) {
- lock_pid = get_lock_pid( data, i, large_file_format);
- 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) {
- END_PROFILE(SMBlockingX);
- return ERROR_DOS(ERRDOS,ERRnoaccess);
- }
-
- DEBUG(10,("reply_lockingX: lock start=%.0f, len=%.0f for pid %u, file %s\n",
- (double)offset, (double)count, (unsigned int)lock_pid, fsp->fsp_name ));
-
- status = do_lock(fsp,conn,lock_pid, count,offset,
- ((locktype & 1) ? READ_LOCK : WRITE_LOCK));
- if (NT_STATUS_V(status)) {
- if ((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)) {
- END_PROFILE(SMBlockingX);
- 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) {
- /*
- * 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--) {
- lock_pid = get_lock_pid( data, i, large_file_format);
- 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) {
- END_PROFILE(SMBlockingX);
- return ERROR_DOS(ERRDOS,ERRnoaccess);
- }
-
- do_unlock(fsp,conn,lock_pid,count,offset);
- }
- END_PROFILE(SMBlockingX);
- return ERROR_NT(status);
+ release_level_2_oplocks_on_change(fsp);
+
+ /* Data now points at the beginning of the list
+ of smb_unlkrng structs */
+ for(i = 0; i < (int)num_ulocks; i++) {
+ lock_pid = get_lock_pid( data, i, large_file_format);
+ 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) {
+ END_PROFILE(SMBlockingX);
+ return ERROR(ERRDOS,ERRnoaccess);
+ }
+
+ DEBUG(10,("reply_lockingX: unlock start=%.0f, len=%.0f for pid %u, file %s\n",
+ (double)offset, (double)count, (unsigned int)lock_pid, fsp->fsp_name ));
+
+ if(!do_unlock(fsp,conn,lock_pid,count,offset, &eclass, &ecode)) {
+ END_PROFILE(SMBlockingX);
+ return ERROR(eclass,ecode);
+ }
+ }
+
+ /* Setup the timeout in seconds. */
+ lock_timeout = ((lock_timeout == -1) ? -1 : lock_timeout/1000);
+
+ /* Now do any requested locks */
+ 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++) {
+ lock_pid = get_lock_pid( data, i, large_file_format);
+ 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) {
+ END_PROFILE(SMBlockingX);
+ return ERROR(ERRDOS,ERRnoaccess);
+ }
+
+ DEBUG(10,("reply_lockingX: lock start=%.0f, len=%.0f for pid %u, file %s\n",
+ (double)offset, (double)count, (unsigned int)lock_pid, fsp->fsp_name ));
+
+ if(!do_lock(fsp,conn,lock_pid, 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)) {
+ END_PROFILE(SMBlockingX);
+ return -1;
}
+ }
+ break;
+ }
+ }
- set_message(outbuf,2,0,True);
-
- DEBUG( 3, ( "lockingX fnum=%d type=%d num_locks=%d num_ulocks=%d\n",
- fsp->fnum, (unsigned int)locktype, num_locks, num_ulocks ) );
-
+ /* 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) {
+ /*
+ * 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--) {
+ lock_pid = get_lock_pid( data, i, large_file_format);
+ 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) {
END_PROFILE(SMBlockingX);
- return chain_reply(inbuf,outbuf,length,bufsize);
+ return ERROR(ERRDOS,ERRnoaccess);
+ }
+
+ do_unlock(fsp,conn,lock_pid,count,offset,&dummy1,&dummy2);
+ }
+ END_PROFILE(SMBlockingX);
+ return ERROR(eclass,ecode);
+ }
+
+ set_message(outbuf,2,0,True);
+
+ DEBUG( 3, ( "lockingX fnum=%d type=%d num_locks=%d num_ulocks=%d\n",
+ fsp->fnum, (unsigned int)locktype, num_locks, num_ulocks ) );
+
+ END_PROFILE(SMBlockingX);
+ return chain_reply(inbuf,outbuf,length,bufsize);
}
+/* Back from the dead for OS/2..... JRA. */
+
/****************************************************************************
- Reply to a SMBreadbmpx (read block multiplex) request.
+ Reply to a SMBreadbmpx (read block multiplex) request
****************************************************************************/
int reply_readbmpx(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
@@ -3807,13 +4572,14 @@ int reply_readbmpx(connection_struct *conn, char *inbuf,char *outbuf,int length,
/* this function doesn't seem to work - disable by default */
if (!lp_readbmpx()) {
END_PROFILE(SMBreadBmpx);
- return ERROR_DOS(ERRSRV,ERRuseSTD);
+ return(ERROR(ERRSRV,ERRuseSTD));
}
outsize = set_message(outbuf,8,0,True);
CHECK_FSP(fsp,conn);
CHECK_READ(fsp);
+ CHECK_ERROR(fsp);
startpos = IVAL(inbuf,smb_vwv1);
maxcount = SVAL(inbuf,smb_vwv3);
@@ -3828,14 +4594,14 @@ int reply_readbmpx(connection_struct *conn, char *inbuf,char *outbuf,int length,
tcount = maxcount;
total_read = 0;
- if (is_locked(fsp,conn,(SMB_BIG_UINT)maxcount,(SMB_BIG_UINT)startpos, READ_LOCK,False)) {
+ if (is_locked(fsp,conn,(SMB_BIG_UINT)maxcount,(SMB_BIG_UINT)startpos, READ_LOCK, False)) {
END_PROFILE(SMBreadBmpx);
- return ERROR_DOS(ERRDOS,ERRlock);
+ return(ERROR(ERRDOS,ERRlock));
}
do {
size_t N = MIN(max_per_packet,tcount-total_read);
-
+
nread = read_file(fsp,data,startpos,N);
if (nread <= 0)
@@ -3862,65 +4628,6 @@ int reply_readbmpx(connection_struct *conn, char *inbuf,char *outbuf,int length,
}
/****************************************************************************
- Reply to a SMBsetattrE.
-****************************************************************************/
-
-int reply_setattrE(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
-{
- struct utimbuf unix_times;
- int outsize = 0;
- files_struct *fsp = file_fsp(inbuf,smb_vwv0);
- START_PROFILE(SMBsetattrE);
-
- outsize = set_message(outbuf,0,0,True);
-
- CHECK_FSP(fsp,conn);
-
- /* Convert the DOS times into unix times. Ignore create
- time as UNIX can't set this.
- */
- 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" );
- }
- END_PROFILE(SMBsetattrE);
- 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(file_utime(conn, fsp->fsp_name, &unix_times)) {
- END_PROFILE(SMBsetattrE);
- return ERROR_DOS(ERRDOS,ERRnoaccess);
- }
-
- DEBUG( 3, ( "reply_setattrE fnum=%d actime=%d modtime=%d\n",
- fsp->fnum, (int)unix_times.actime, (int)unix_times.modtime ) );
-
- END_PROFILE(SMBsetattrE);
- return(outsize);
-}
-
-
-/* Back from the dead for OS/2..... JRA. */
-
-/****************************************************************************
Reply to a SMBwritebmpx (write block multiplex primary) request.
****************************************************************************/
@@ -3955,7 +4662,7 @@ int reply_writebmpx(connection_struct *conn, char *inbuf,char *outbuf, int size,
if (is_locked(fsp,conn,(SMB_BIG_UINT)tcount,(SMB_BIG_UINT)startpos,WRITE_LOCK,False)) {
END_PROFILE(SMBwriteBmpx);
- return(ERROR_DOS(ERRDOS,ERRlock));
+ return(ERROR(ERRDOS,ERRlock));
}
nwritten = write_file(fsp,data,startpos,numtowrite);
@@ -3979,10 +4686,11 @@ int reply_writebmpx(connection_struct *conn, char *inbuf,char *outbuf, int size,
wbms = fsp->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"));
END_PROFILE(SMBwriteBmpx);
- return(ERROR_DOS(ERRSRV,ERRnoresource));
+ return(ERROR(ERRSRV,ERRnoresource));
}
wbms->wr_mode = write_through;
wbms->wr_discard = False; /* No errors yet */
@@ -3992,24 +4700,23 @@ int reply_writebmpx(connection_struct *conn, char *inbuf,char *outbuf, int size,
fsp->wbmpx_ptr = wbms;
}
- /* We are returning successfully, set the message type back to
- SMBwritebmpx */
+ /* We are returning successfully, set the message type back to SMBwritebmpx */
CVAL(outbuf,smb_com) = SMBwriteBmpx;
outsize = set_message(outbuf,1,0,True);
-
+
SSVALS(outbuf,smb_vwv0,-1); /* We don't support smb_remaining */
DEBUG( 3, ( "writebmpx fnum=%d num=%d wrote=%d\n",
- fsp->fnum, (int)numtowrite, (int)nwritten ) );
+ fsp->fnum, (int)numtowrite, (int)nwritten ) );
if (write_through && tcount==nwritten) {
- /* We need to send both a primary and a secondary response */
+ /* We need to send both a primary and a secondary response. */
smb_setlen(outbuf,outsize - 4);
if (!send_smb(smbd_server_fd(),outbuf))
- exit_server("reply_writebmpx: send_smb failed.\n");
+ exit_server("reply_writeBmpx : send_smb failed.\n");
- /* Now the secondary */
+ /* Now the secondary. */
outsize = set_message(outbuf,1,0,True);
CVAL(outbuf,smb_com) = SMBwritec;
SSVAL(outbuf,smb_vwv0,nwritten);
@@ -4051,8 +4758,7 @@ int reply_writebs(connection_struct *conn, char *inbuf,char *outbuf, int dum_siz
/* We need to send an SMBwriteC response, not an SMBwritebs */
CVAL(outbuf,smb_com) = SMBwritec;
- /* This fd should have an auxiliary struct attached,
- check that it does */
+ /* This fd should have an auxiliary struct attached, check that it does */
wbms = fsp->wbmpx_ptr;
if(!wbms) {
END_PROFILE(SMBwriteBs);
@@ -4080,7 +4786,7 @@ int reply_writebs(connection_struct *conn, char *inbuf,char *outbuf, int dum_siz
free((char *)wbms);
fsp->wbmpx_ptr = NULL;
END_PROFILE(SMBwriteBs);
- return(ERROR_DOS(ERRHRD,ERRdiskfull));
+ return(ERROR(ERRHRD,ERRdiskfull));
}
END_PROFILE(SMBwriteBs);
return(CACHE_ERROR(wbms,ERRHRD,ERRdiskfull));
@@ -4110,7 +4816,64 @@ int reply_writebs(connection_struct *conn, char *inbuf,char *outbuf, int dum_siz
}
/****************************************************************************
- Reply to a SMBgetattrE.
+ Reply to a SMBsetattrE.
+****************************************************************************/
+
+int reply_setattrE(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
+{
+ struct utimbuf unix_times;
+ int outsize = 0;
+ files_struct *fsp = file_fsp(inbuf,smb_vwv0);
+ START_PROFILE(SMBsetattrE);
+
+ outsize = set_message(outbuf,0,0,True);
+
+ CHECK_FSP(fsp,conn);
+
+ /* Convert the DOS times into unix times. Ignore create
+ time as UNIX can't set this.
+ */
+ 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" );
+ }
+ END_PROFILE(SMBsetattrE);
+ 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(file_utime(conn, fsp->fsp_name, &unix_times)) {
+ END_PROFILE(SMBsetattrE);
+ return(ERROR(ERRDOS,ERRnoaccess));
+ }
+
+ DEBUG( 3, ( "reply_setattrE fnum=%d actime=%d modtime=%d\n",
+ fsp->fnum, (int)unix_times.actime, (int)unix_times.modtime ) );
+
+ END_PROFILE(SMBsetattrE);
+ return(outsize);
+}
+
+
+/****************************************************************************
+ reply to a SMBgetattrE
****************************************************************************/
int reply_getattrE(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)