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