diff options
Diffstat (limited to 'source/smbd/reply.c')
-rw-r--r-- | source/smbd/reply.c | 2401 |
1 files changed, 1582 insertions, 819 deletions
diff --git a/source/smbd/reply.c b/source/smbd/reply.c index 845fabda926..8e97857ef68 100644 --- a/source/smbd/reply.c +++ b/source/smbd/reply.c @@ -3,8 +3,7 @@ Version 1.9. Main SMB reply routines Copyright (C) Andrew Tridgell 1992-1998 - Copyright (C) Andrew Bartlett 2001 - + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or @@ -29,6 +28,7 @@ /* look in server.c for some explanation of these variables */ extern int Protocol; +extern int DEBUGLEVEL; extern int max_send; extern int max_recv; extern char magic_char; @@ -37,12 +37,24 @@ extern BOOL case_preserve; extern BOOL short_case_preserve; extern userdom_struct current_user_info; extern pstring global_myname; +extern fstring global_myworkgroup; extern int global_oplock_break; uint32 global_client_caps = 0; unsigned int smb_echo_count = 0; -extern fstring remote_machine; -extern BOOL global_encrypted_passwords_negotiated; +/**************************************************************************** +report a possible attack via the password buffer overflow bug +****************************************************************************/ + +static void overflow_attack(int len) +{ + if( DEBUGLVL( 0 ) ) { + dbgtext( "ERROR: Invalid password length %d.\n", len ); + dbgtext( "Your machine may be under attack by someone " ); + dbgtext( "attempting to exploit an old bug.\n" ); + dbgtext( "Attack was from IP = %s.\n", client_addr() ); + } +} /**************************************************************************** @@ -55,7 +67,7 @@ int reply_special(char *inbuf,char *outbuf) int msg_type = CVAL(inbuf,0); int msg_flags = CVAL(inbuf,1); pstring name1,name2; - + extern fstring remote_machine; extern fstring local_machine; int len; char name_type = 0; @@ -106,9 +118,8 @@ int reply_special(char *inbuf,char *outbuf) break; } - /* only add the client's machine name to the list - of possibly valid usernames if we are operating - in share mode security */ + /* add it as a possible user name if we + are in share mode security */ if (lp_security() == SEC_SHARE) { add_session_user(remote_machine); } @@ -116,7 +127,9 @@ int reply_special(char *inbuf,char *outbuf) reload_services(True); reopen_logs(); - claim_connection(NULL,"",MAXSTATUS,True); + if (lp_status(-1)) { + claim_connection(NULL,"",MAXSTATUS,True); + } break; @@ -144,6 +157,53 @@ int reply_special(char *inbuf,char *outbuf) } +/******************************************************************* +work out what error to give to a failed connection +********************************************************************/ + +static int connection_error(char *inbuf,char *outbuf,int ecode) +{ + if (ecode == ERRnoipc || ecode == ERRnosuchshare) + return(ERROR(ERRDOS,ecode)); + + return(ERROR(ERRSRV,ecode)); +} + +/**************************************************************************** + parse a share descriptor string +****************************************************************************/ + +static void parse_connect(char *p,char *service,char *user, + char *password,int *pwlen,char *dev) +{ + char *p2; + + DEBUG(4,("parsing connect string %s\n",p)); + + p2 = strrchr(p,'\\'); + if (p2 == NULL) + fstrcpy(service,p); + else + fstrcpy(service,p2+1); + + p += strlen(p) + 2; + + fstrcpy(password,p); + *pwlen = strlen(password); + + p += strlen(p) + 2; + + fstrcpy(dev,p); + + *user = 0; + p = strchr(service,'%'); + if (p != NULL) + { + *p = 0; + fstrcpy(user,p+1); + } +} + /**************************************************************************** Reply to a tcon. ****************************************************************************/ @@ -151,34 +211,54 @@ int reply_special(char *inbuf,char *outbuf) int reply_tcon(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize) { + BOOL doencrypt = SMBENCRYPT(); pstring service; + pstring user; pstring password; pstring dev; int outsize = 0; uint16 vuid = SVAL(inbuf,smb_uid); int pwlen=0; - NTSTATUS nt_status; - char *p; - + int ecode = -1; START_PROFILE(SMBtcon); - *service = *password = *dev = 0; + *service = *user = *password = *dev = 0; - p = smb_buf(inbuf)+1; - p += srvstr_pull(inbuf, service, p, sizeof(service), -1, STR_TERMINATE) + 1; - p += srvstr_pull(inbuf, password, p, sizeof(password), -1, STR_TERMINATE) + 1; - p += srvstr_pull(inbuf, dev, p, sizeof(dev), -1, STR_TERMINATE) + 1; + parse_connect(smb_buf(inbuf)+1,service,user,password,&pwlen,dev); - p = strrchr_m(service,'\\'); - if (p) { - pstrcpy(service, p+1); + /* + * If the vuid is valid, we should be using that.... + */ + + if (*user == '\0' && (lp_security() != SEC_SHARE) && validated_username(vuid)) { + pstrcpy(user,validated_username(vuid)); } - conn = make_connection(service,password,pwlen,dev,vuid,&nt_status); + /* + * Ensure the user and password names are in UNIX codepage format. + */ + + pstrcpy(user,dos_to_unix(user,False)); + if (!doencrypt) + pstrcpy(password,dos_to_unix(password,False)); + + /* + * Pass the user through the NT -> unix user mapping + * function. + */ + + (void)map_username(user); + + /* + * Do any UNIX username case mangling. + */ + (void)Get_Pwnam( user, True); + + conn = make_connection(service,user,password,pwlen,dev,vuid,&ecode); if (!conn) { END_PROFILE(SMBtcon); - return ERROR_NT(nt_status); + return(connection_error(inbuf,outbuf,ecode)); } outsize = set_message(outbuf,2,0,True); @@ -186,8 +266,8 @@ int reply_tcon(connection_struct *conn, SSVAL(outbuf,smb_vwv1,conn->cnum); SSVAL(outbuf,smb_tid,conn->cnum); - DEBUG(3,("tcon service=%s cnum=%d\n", - service, conn->cnum)); + DEBUG(3,("tcon service=%s user=%s cnum=%d\n", + service, user, conn->cnum)); END_PROFILE(SMBtcon); return(outsize); @@ -200,16 +280,18 @@ int reply_tcon(connection_struct *conn, int reply_tcon_and_X(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize) { fstring service; + pstring user; pstring password; pstring devicename; - NTSTATUS nt_status; + BOOL doencrypt = SMBENCRYPT(); + int ecode = -1; uint16 vuid = SVAL(inbuf,smb_uid); int passlen = SVAL(inbuf,smb_vwv3); - pstring path; - char *p, *q; + char *path; + char *p; START_PROFILE(SMBtconX); - *service = *password = *devicename = 0; + *service = *user = *password = *devicename = 0; /* we might have to close an old one */ if ((SVAL(inbuf,smb_vwv2) & 0x1) && conn) { @@ -217,65 +299,91 @@ int reply_tcon_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt } if (passlen > MAX_PASS_LEN) { - return ERROR_DOS(ERRDOS,ERRbuftoosmall); + overflow_attack(passlen); + return(ERROR(ERRDOS,ERRbuftoosmall)); } memcpy(password,smb_buf(inbuf),passlen); password[passlen]=0; - p = smb_buf(inbuf) + passlen; - p += srvstr_pull(inbuf, path, p, sizeof(path), -1, STR_TERMINATE); + path = smb_buf(inbuf) + passlen; if (passlen != 24) { if (strequal(password," ")) *password = 0; passlen = strlen(password); } - + /* * the service name can be either: \\server\share * or share directly like on the DELL PowerVault 705 */ if (*path=='\\') { - q = strchr_m(path+2,'\\'); - if (!q) { + p = strchr(path+2,'\\'); + if (!p) { END_PROFILE(SMBtconX); - return(ERROR_DOS(ERRDOS,ERRnosuchshare)); + return(ERROR(ERRDOS,ERRnosuchshare)); } - fstrcpy(service,q+1); + fstrcpy(service,p+1); } else fstrcpy(service,path); - p += srvstr_pull(inbuf, devicename, p, sizeof(devicename), 6, STR_ASCII); - + p = strchr(service,'%'); + if (p) { + *p++ = 0; + fstrcpy(user,p); + } + StrnCpy(devicename,path + strlen(path) + 1,6); DEBUG(4,("Got device type %s\n",devicename)); - conn = make_connection(service,password,passlen,devicename,vuid,&nt_status); + /* + * If the vuid is valid, we should be using that.... + */ + + if (*user == '\0' && (lp_security() != SEC_SHARE) && validated_username(vuid)) { + pstrcpy(user,validated_username(vuid)); + } + + /* + * Ensure the user and password names are in UNIX codepage format. + */ + + pstrcpy(user,dos_to_unix(user,False)); + if (!doencrypt) + pstrcpy(password,dos_to_unix(password,False)); + + /* + * Pass the user through the NT -> unix user mapping + * function. + */ + + (void)map_username(user); + + /* + * Do any UNIX username case mangling. + */ + (void)Get_Pwnam(user, True); + + conn = make_connection(service,user,password,passlen,devicename,vuid,&ecode); if (!conn) { END_PROFILE(SMBtconX); - return ERROR_NT(nt_status); + return(connection_error(inbuf,outbuf,ecode)); } if (Protocol < PROTOCOL_NT1) { - set_message(outbuf,2,0,True); - p = smb_buf(outbuf); - p += srvstr_push(outbuf, p, devicename, -1, - STR_TERMINATE|STR_ASCII); - set_message_end(outbuf,p); + set_message(outbuf,2,strlen(devicename)+1,True); + pstrcpy(smb_buf(outbuf),devicename); } else { - /* NT sets the fstype of IPC$ to the null string */ - char *fsname = IS_IPC(conn) ? "" : lp_fstype(SNUM(conn)); + char *fsname = lp_fstype(SNUM(conn)); - set_message(outbuf,3,0,True); + set_message(outbuf,3,3,True); p = smb_buf(outbuf); - p += srvstr_push(outbuf, p, devicename, -1, - STR_TERMINATE|STR_ASCII); - p += srvstr_push(outbuf, p, fsname, -1, - STR_TERMINATE); + pstrcpy(p,devicename); p = skip_string(p,1); /* device name */ + pstrcpy(p,fsname); p = skip_string(p,1); /* filesystem type e.g NTFS */ - set_message_end(outbuf,p); + set_message(outbuf,3,PTR_DIFF(p,smb_buf(outbuf)),False); /* what does setting this bit do? It is set by NT4 and may affect the ability to autorun mounted cdroms */ @@ -285,8 +393,8 @@ int reply_tcon_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt } - DEBUG(3,("tconX service=%s \n", - service)); + DEBUG(3,("tconX service=%s user=%s\n", + service, user)); /* set the incoming and outgoing tid to the just created one */ SSVAL(inbuf,smb_tid,conn->cnum); @@ -308,10 +416,9 @@ int reply_unknown(char *inbuf,char *outbuf) DEBUG(0,("unknown command type (%s): type=%d (0x%X)\n", smb_fn_name(type), type, type)); - return(ERROR_DOS(ERRSRV,ERRunknownsmb)); + return(ERROR(ERRSRV,ERRunknownsmb)); } - /**************************************************************************** reply to an ioctl ****************************************************************************/ @@ -335,7 +442,7 @@ int reply_ioctl(connection_struct *conn, break; default: END_PROFILE(SMBioctl); - return(ERROR_DOS(ERRSRV,ERRnosupport)); + return(ERROR(ERRSRV,ERRnosupport)); } outsize = set_message(outbuf,8,replysize+1,True); @@ -348,8 +455,8 @@ int reply_ioctl(connection_struct *conn, { case IOCTL_QUERY_JOB_INFO: SSVAL(p,0,fsp->print_jobid); /* Job number */ - srvstr_push(outbuf, p+2, global_myname, 15, STR_TERMINATE|STR_ASCII); - srvstr_push(outbuf, p+18, lp_servicename(SNUM(conn)), 13, STR_TERMINATE|STR_ASCII); + StrnCpy(p+2, global_myname, 15); /* Our NetBIOS name */ + StrnCpy(p+18, lp_servicename(SNUM(conn)), 13); /* Service name */ break; } @@ -358,6 +465,632 @@ int reply_ioctl(connection_struct *conn, } /**************************************************************************** + Always return an error: it's just a matter of which one... + FIXME: memory leak - no call to pdb_free_sam() --jerry + ****************************************************************************/ + +static int session_trust_account(connection_struct *conn, char *inbuf, char *outbuf, char *user, + char *smb_passwd, int smb_passlen, + char *smb_nt_passwd, int smb_nt_passlen) +{ + SAM_ACCOUNT *sam_trust_acct = NULL; /* check if trust account exists */ + uint16 acct_ctrl; + + if (lp_security() == SEC_USER) { + pdb_init_sam(&sam_trust_acct); + pdb_getsampwnam(sam_trust_acct, user); + } else { + DEBUG(0,("session_trust_account: Trust account %s only supported with security = user\n", user)); + return(ERROR_BOTH(NT_STATUS_LOGON_FAILURE,ERRSRV,ERRbadpw)); + } + + if (sam_trust_acct == NULL) { + /* lkclXXXX: workstation entry doesn't exist */ + DEBUG(0,("session_trust_account: Trust account %s user doesn't exist\n",user)); + return(ERROR_BOTH(NT_STATUS_NO_SUCH_USER,ERRDOS,1317)); + } else { + if ((smb_passlen != 24) || (smb_nt_passlen != 24)) { + DEBUG(0,("session_trust_account: Trust account %s - password length wrong.\n", user)); + return(ERROR_BOTH(NT_STATUS_LOGON_FAILURE,ERRSRV,ERRbadpw)); + } + + if (!smb_password_ok(sam_trust_acct, NULL, (unsigned char *)smb_passwd, (unsigned char *)smb_nt_passwd)) { + DEBUG(0,("session_trust_account: Trust Account %s - password failed\n", user)); + return(ERROR_BOTH(NT_STATUS_LOGON_FAILURE,ERRSRV,ERRbadpw)); + } + + acct_ctrl = pdb_get_acct_ctrl(sam_trust_acct); + if (acct_ctrl & ACB_DOMTRUST) { + DEBUG(0,("session_trust_account: Domain trust account %s denied by server\n",user)); + return(ERROR_BOTH(NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT,ERRDOS,1807)); + } + + if (acct_ctrl & ACB_SVRTRUST) { + DEBUG(0,("session_trust_account: Server trust account %s denied by server\n",user)); + return(ERROR_BOTH(NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT,ERRDOS,1809)); + } + + if (acct_ctrl & ACB_WSTRUST) { + DEBUG(4,("session_trust_account: Wksta trust account %s denied by server\n", user)); + return(ERROR_BOTH(NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT,ERRDOS,1808)); + } + } + + /* don't know what to do: indicate logon failure */ + return(ERROR_BOTH(NT_STATUS_LOGON_FAILURE,ERRDOS,1326)); +} + +/**************************************************************************** + Create a UNIX user on demand. +****************************************************************************/ + +int smb_create_user(char *unix_user, char *homedir) +{ + pstring add_script; + int ret; + + pstrcpy(add_script, lp_adduser_script()); + if (! *add_script) return -1; + all_string_sub(add_script, "%u", unix_user, sizeof(pstring)); + if (homedir) + all_string_sub(add_script, "%H", homedir, sizeof(pstring)); + ret = smbrun(add_script,NULL); + DEBUG(3,("smb_create_user: Running the command `%s' gave %d\n",add_script,ret)); + return ret; +} + +/**************************************************************************** + Delete a UNIX user on demand. +****************************************************************************/ + +static int smb_delete_user(char *unix_user) +{ + pstring del_script; + int ret; + + pstrcpy(del_script, lp_deluser_script()); + if (! *del_script) return -1; + all_string_sub(del_script, "%u", unix_user, sizeof(pstring)); + ret = smbrun(del_script,NULL); + DEBUG(3,("smb_delete_user: Running the command `%s' gave %d\n",del_script,ret)); + return ret; +} + +/**************************************************************************** + Check user is in correct domain if required +****************************************************************************/ + +static BOOL check_domain_match(char *user, char *domain) +{ + /* + * If we aren't serving to trusted domains, we must make sure that + * the validation request comes from an account in the same domain + * as the Samba server + */ + + if (!lp_allow_trusted_domains() && + !strequal(lp_workgroup(), domain) ) { + DEBUG(1, ("check_domain_match: Attempt to connect as user %s from domain %s denied.\n", user, domain)); + return False; + } else { + return True; + } +} + +/**************************************************************************** + Check for a valid username and password in security=server mode. +****************************************************************************/ + +static BOOL check_server_security(char *orig_user, char *domain, char *unix_user, + char *smb_apasswd, int smb_apasslen, + char *smb_ntpasswd, int smb_ntpasslen) +{ + BOOL ret = False; + + if(lp_security() != SEC_SERVER) + return False; + + if (!check_domain_match(orig_user, domain)) + return False; + + ret = server_validate(orig_user, domain, + smb_apasswd, smb_apasslen, + smb_ntpasswd, smb_ntpasslen); + + if(ret) { + struct passwd *pwd = NULL; + + /* + * User validated ok against Domain controller. + * If the admin wants us to try and create a UNIX + * user on the fly, do so. + * Note that we can never delete users when in server + * level security as we never know if it was a failure + * due to a bad password, or the user really doesn't exist. + */ + + if(lp_adduser_script() && !(pwd = smb_getpwnam(unix_user,True))) + smb_create_user(unix_user, NULL); + + if(lp_adduser_script() && pwd) { + SMB_STRUCT_STAT st; + + /* + * Also call smb_create_user if the users home directory + * doesn't exist. Used with winbindd to allow the script to + * create the home directory for a user mapped with winbindd. + */ + + if (pwd->pw_dir && (sys_stat(pwd->pw_dir, &st) == -1) && (errno == ENOENT)) + smb_create_user(unix_user, pwd->pw_dir); + } + } + + return ret; +} + +/**************************************************************************** + Check for a valid username and password in security=domain mode. +****************************************************************************/ + +static BOOL check_domain_security(char *orig_user, char *domain, char *unix_user, + char *smb_apasswd, int smb_apasslen, + char *smb_ntpasswd, int smb_ntpasslen) +{ + BOOL ret = False; + BOOL user_exists = True; + struct passwd *pwd = NULL; + + if(lp_security() != SEC_DOMAIN) + return False; + + if (!check_domain_match(orig_user, domain)) + return False; + + ret = domain_client_validate(orig_user, domain, + smb_apasswd, smb_apasslen, + smb_ntpasswd, smb_ntpasslen, + &user_exists); + + if(ret) { + /* + * User validated ok against Domain controller. + * If the admin wants us to try and create a UNIX + * user on the fly, do so. + */ + if(user_exists && lp_adduser_script() && !(pwd = smb_getpwnam(unix_user,True))) { + smb_create_user(unix_user, NULL); + } + + if(lp_adduser_script() && pwd) { + SMB_STRUCT_STAT st; + + /* + * Also call smb_create_user if the users home directory + * doesn't exist. Used with winbindd to allow the script to + * create the home directory for a user mapped with winbindd. + */ + + if (pwd->pw_dir && (sys_stat(pwd->pw_dir, &st) == -1) && (errno == ENOENT)) + smb_create_user(unix_user, pwd->pw_dir); + } + + } else { + /* + * User failed to validate ok against Domain controller. + * If the failure was "user doesn't exist" and admin + * wants us to try and delete that UNIX user on the fly, + * do so. + */ + if(!user_exists && lp_deluser_script() && smb_getpwnam(unix_user,True)) { + smb_delete_user(unix_user); + } + } + + return ret; +} + +/**************************************************************************** + Reply to a session setup command. +****************************************************************************/ + +int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize) +{ + int sess_vuid; + gid_t gid; + uid_t uid; + int smb_bufsize; + int smb_apasslen = 0; + pstring smb_apasswd; + int smb_ntpasslen = 0; + pstring smb_ntpasswd; + BOOL valid_nt_password = False; + BOOL valid_lm_password = False; + pstring user; + pstring orig_user; + BOOL guest=False; + static BOOL done_sesssetup = False; + BOOL doencrypt = SMBENCRYPT(); + fstring domain; + START_PROFILE(SMBsesssetupX); + + *smb_apasswd = 0; + *smb_ntpasswd = 0; + *domain = 0; + + smb_bufsize = SVAL(inbuf,smb_vwv2); + + if (Protocol < PROTOCOL_NT1) { + smb_apasslen = SVAL(inbuf,smb_vwv7); + if (smb_apasslen > MAX_PASS_LEN) { + overflow_attack(smb_apasslen); + return(ERROR(ERRDOS,ERRbuftoosmall)); + } + + memcpy(smb_apasswd,smb_buf(inbuf),smb_apasslen); + smb_apasswd[smb_apasslen] = 0; + pstrcpy(user,smb_buf(inbuf)+smb_apasslen); + /* + * Incoming user is in DOS codepage format. Convert + * to UNIX. + */ + pstrcpy(user,dos_to_unix(user,False)); + + if (!doencrypt && (lp_security() != SEC_SERVER)) { + smb_apasslen = strlen(smb_apasswd); + } + } else { + uint16 passlen1 = SVAL(inbuf,smb_vwv7); + uint16 passlen2 = SVAL(inbuf,smb_vwv8); + enum remote_arch_types ra_type = get_remote_arch(); + char *p = smb_buf(inbuf); + + if(global_client_caps == 0) + global_client_caps = IVAL(inbuf,smb_vwv11); + + /* client_caps is used as final determination if client is NT or Win95. + This is needed to return the correct error codes in some + circumstances. + */ + + if(ra_type == RA_WINNT || ra_type == RA_WIN2K || ra_type == RA_WIN95) { + if(!(global_client_caps & (CAP_NT_SMBS | CAP_STATUS32))) { + set_remote_arch( RA_WIN95); + } + } + + if (passlen1 != 24 && passlen2 != 24) + doencrypt = False; + + if (passlen1 > MAX_PASS_LEN) { + overflow_attack(passlen1); + return(ERROR(ERRDOS,ERRbuftoosmall)); + } + + passlen1 = MIN(passlen1, MAX_PASS_LEN); + passlen2 = MIN(passlen2, MAX_PASS_LEN); + + if(!doencrypt) { + /* both Win95 and WinNT stuff up the password lengths for + non-encrypting systems. Uggh. + + if passlen1==24 its a win95 system, and its setting the + password length incorrectly. Luckily it still works with the + default code because Win95 will null terminate the password + anyway + + if passlen1>0 and passlen2>0 then maybe its a NT box and its + setting passlen2 to some random value which really stuffs + things up. we need to fix that one. */ + + if (passlen1 > 0 && passlen2 > 0 && passlen2 != 24 && passlen2 != 1) + passlen2 = 0; + } + + if (lp_restrict_anonymous()) { + /* there seems to be no reason behind the differences in MS clients formatting + * various info like the domain, NativeOS, and NativeLanMan fields. Win95 + * in particular seems to have an extra null byte between the username and the + * domain, or the password length calculation is wrong, which throws off the + * string extraction routines below. This makes the value of domain be the + * empty string, which fails the restrict anonymous check further down. + * This compensates for that, and allows browsing to work in mixed NT and + * win95 environments even when restrict anonymous is true. AAB + */ + dump_data(100, p, 0x70); + DEBUG(9, ("passlen1=%d, passlen2=%d\n", passlen1, passlen2)); + if (ra_type == RA_WIN95 && !passlen1 && !passlen2 && p[0] == 0 && p[1] == 0) { + DEBUG(0, ("restrict anonymous parameter used in a win95 environment!\n")); + DEBUG(0, ("client is win95 and broken passlen1 offset -- attempting fix\n")); + DEBUG(0, ("if win95 cilents are having difficulty browsing, you will be unable to use restrict anonymous\n")); + passlen1 = 1; + } + } + + if(doencrypt || ((lp_security() == SEC_SERVER) || (lp_security() == SEC_DOMAIN))) { + /* Save the lanman2 password and the NT md4 password. */ + smb_apasslen = passlen1; + memcpy(smb_apasswd,p,smb_apasslen); + smb_apasswd[smb_apasslen] = 0; + smb_ntpasslen = passlen2; + memcpy(smb_ntpasswd,p+passlen1,smb_ntpasslen); + smb_ntpasswd[smb_ntpasslen] = 0; + + /* + * Ensure the plaintext passwords are in UNIX format. + */ + if(!doencrypt) { + pstrcpy(smb_apasswd,dos_to_unix(smb_apasswd,False)); + pstrcpy(smb_ntpasswd,dos_to_unix(smb_ntpasswd,False)); + } + + } else { + /* we use the first password that they gave */ + smb_apasslen = passlen1; + StrnCpy(smb_apasswd,p,smb_apasslen); + /* + * Ensure the plaintext password is in UNIX format. + */ + pstrcpy(smb_apasswd,dos_to_unix(smb_apasswd,False)); + + /* trim the password */ + smb_apasslen = strlen(smb_apasswd); + + /* wfwg sometimes uses a space instead of a null */ + if (strequal(smb_apasswd," ")) { + smb_apasslen = 0; + *smb_apasswd = 0; + } + } + + p += passlen1 + passlen2; + fstrcpy(user,p); + p = skip_string(p,1); + /* + * Incoming user and domain are in DOS codepage format. Convert + * to UNIX. + */ + pstrcpy(user,dos_to_unix(user,False)); + fstrcpy(domain, dos_to_unix(p, False)); + DEBUG(3,("Domain=[%s] NativeOS=[%s] NativeLanMan=[%s]\n", + domain,skip_string(p,1),skip_string(p,2))); + } + + /* don't allow strange characters in usernames or domains */ + alpha_strcpy(user, user, ". _-$", sizeof(user)); + alpha_strcpy(domain, domain, ". _-", sizeof(domain)); + if (strstr(user, "..") || strstr(domain,"..")) { + return ERROR_BOTH(NT_STATUS_LOGON_FAILURE,ERRSRV,ERRbadpw); + } + + DEBUG(3,("sesssetupX:name=[%s]\n",user)); + + /* If name ends in $ then I think it's asking about whether a */ + /* computer with that name (minus the $) has access. For now */ + /* say yes to everything ending in $. */ + + if (*user && (user[strlen(user) - 1] == '$') && (smb_apasslen == 24) && (smb_ntpasslen == 24)) { + END_PROFILE(SMBsesssetupX); + return session_trust_account(conn, inbuf, outbuf, user, + smb_apasswd, smb_apasslen, + smb_ntpasswd, smb_ntpasslen); + } + + if (done_sesssetup && lp_restrict_anonymous()) { + /* tests show that even if browsing is done over already validated connections + * without a username and password the domain is still provided, which it + * wouldn't be if it was a purely anonymous connection. So, in order to + * restrict anonymous, we only deny connections that have no session + * information. If a domain has been provided, then it's not a purely + * anonymous connection. AAB + */ + if (!*user && !*smb_apasswd && !*domain) { + DEBUG(0, ("restrict anonymous is True and anonymous connection attempted. Denying access.\n")); + END_PROFILE(SMBsesssetupX); + return(ERROR(ERRDOS,ERRnoaccess)); + } + } + + /* If no username is sent use the guest account */ + if (!*user) { + pstrcpy(user,lp_guestaccount(-1)); + guest = True; + } + + pstrcpy(current_user_info.smb_name,user); + + reload_services(True); + + /* + * Save the username before mapping. We will use + * the original username sent to us for security=server + * and security=domain checking. + */ + + pstrcpy( orig_user, user); + + /* + * Always try the "DOMAIN\user" lookup first, as this is the most + * specific case. If this fails then try the simple "user" lookup. + */ + + { + pstring dom_user; + + /* Work out who's who */ + + slprintf(dom_user, sizeof(dom_user) - 1,"%s%s%s", + dos_to_unix(domain, False), lp_winbind_separator(), user); + + if (sys_getpwnam(dom_user) != NULL) { + pstrcpy(user, dom_user); + DEBUG(3,("Using unix username %s\n", dom_user)); + } + } + + /* + * Pass the user through the NT -> unix user mapping + * function. + */ + + (void)map_username(user); + + /* + * Do any UNIX username case mangling. + */ + smb_getpwnam(user, True); + + add_session_user(user); + + /* + * Check with orig_user for security=server and + * security=domain. + */ + + if (!guest && !check_server_security(orig_user, domain, user, + smb_apasswd, smb_apasslen, smb_ntpasswd, smb_ntpasslen) && + !check_domain_security(orig_user, domain, user, smb_apasswd, + smb_apasslen, smb_ntpasswd, smb_ntpasslen) && + !check_hosts_equiv(user)) + { + + /* + * If we get here then the user wasn't guest and the remote + * authentication methods failed. Check the authentication + * methods on this local server. + * + * If an NT password was supplied try and validate with that + * first. This is superior as the passwords are mixed case + * 128 length unicode. + */ + + if(smb_ntpasslen) + { + if(!password_ok(user, smb_ntpasswd,smb_ntpasslen,NULL)) + DEBUG(2,("NT Password did not match for user '%s'!\n", user)); + else + valid_nt_password = True; + } + + + /* check the LanMan password only if necessary and if allowed + by lp_lanman_auth() */ + if (!valid_nt_password && lp_lanman_auth()) + { + DEBUG(2,("Defaulting to Lanman password for %s\n", user)); + valid_lm_password = password_ok(user, smb_apasswd,smb_apasslen,NULL); + } + + + /* The true branch will be executed if + (1) the NT password failed (or was not tried), and + (2) LanMan authentication failed (or was disabled) + */ + if (!valid_nt_password && !valid_lm_password) + { + if (lp_security() >= SEC_USER) + { + if (lp_map_to_guest() == NEVER_MAP_TO_GUEST) + { + DEBUG(1,("Rejecting user '%s': authentication failed\n", user)); + END_PROFILE(SMBsesssetupX); + return ERROR_BOTH(NT_STATUS_LOGON_FAILURE,ERRSRV,ERRbadpw); + } + + if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_USER) + { + if (smb_getpwnam(user,True)) + { + DEBUG(1,("Rejecting user '%s': bad password\n", user)); + END_PROFILE(SMBsesssetupX); + return ERROR_BOTH(NT_STATUS_LOGON_FAILURE,ERRSRV,ERRbadpw); + } + } + + /* + * ..else if lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD + * Then always map to guest account - as done below. + */ + } + + if (*smb_apasswd || !smb_getpwnam(user,True)) + pstrcpy(user,lp_guestaccount(-1)); + DEBUG(3,("Registered username %s for guest access\n",user)); + guest = True; + } + } + + if (!smb_getpwnam(user,True)) { + DEBUG(3,("No such user %s [%s] - using guest account\n",user, domain)); + pstrcpy(user,lp_guestaccount(-1)); + guest = True; + } + + if (!strequal(user,lp_guestaccount(-1)) && + lp_servicenumber(user) < 0) + { + add_home_service(user,get_user_home_dir(user)); + } + + + /* it's ok - setup a reply */ + if (Protocol < PROTOCOL_NT1) { + set_message(outbuf,3,0,True); + } else { + char *p; + set_message(outbuf,3,3,True); + p = smb_buf(outbuf); + pstrcpy(p,"Unix"); p = skip_string(p,1); + pstrcpy(p,"Samba "); pstrcat(p,VERSION); p = skip_string(p,1); + pstrcpy(p,global_myworkgroup); unix_to_dos(p, True); p = skip_string(p,1); + set_message(outbuf,3,PTR_DIFF(p,smb_buf(outbuf)),False); + /* perhaps grab OS version here?? */ + } + + /* Set the correct uid in the outgoing and incoming packets + We will use this on future requests to determine which + user we should become. + */ + { + const struct passwd *pw = smb_getpwnam(user,False); + if (!pw) { + DEBUG(1,("Username %s is invalid on this system\n",user)); + END_PROFILE(SMBsesssetupX); + return ERROR_BOTH(NT_STATUS_LOGON_FAILURE,ERRSRV,ERRbadpw); + } + gid = pw->pw_gid; + uid = pw->pw_uid; + } + + if (guest) + SSVAL(outbuf,smb_vwv2,1); + + /* register the name and uid as being validated, so further connections + to a uid can get through without a password, on the same VC */ + + sess_vuid = register_vuid(uid,gid,user,current_user_info.smb_name,domain,guest); + + if (sess_vuid == -1) { + return(ERROR(ERRDOS,ERRnoaccess)); + } + + + SSVAL(outbuf,smb_uid,sess_vuid); + SSVAL(inbuf,smb_uid,sess_vuid); + + if (!done_sesssetup) + max_send = MIN(max_send,smb_bufsize); + + DEBUG(6,("Client requested max send size of %d\n", max_send)); + + done_sesssetup = True; + + END_PROFILE(SMBsesssetupX); + return chain_reply(inbuf,outbuf,length,bufsize); +} + + +/**************************************************************************** reply to a chkpth ****************************************************************************/ int reply_chkpth(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize) @@ -369,8 +1102,8 @@ int reply_chkpth(connection_struct *conn, char *inbuf,char *outbuf, int dum_size BOOL bad_path = False; SMB_STRUCT_STAT sbuf; START_PROFILE(SMBchkpth); - - srvstr_pull(inbuf, name, smb_buf(inbuf) + 1, sizeof(name), -1, STR_TERMINATE); + + pstrcpy(name,smb_buf(inbuf) + 1); RESOLVE_DFSPATH(name, conn, inbuf, outbuf); @@ -383,16 +1116,29 @@ int reply_chkpth(connection_struct *conn, char *inbuf,char *outbuf, int dum_size ok = S_ISDIR(sbuf.st_mode); } - if (!ok) { + if (!ok) + { /* We special case this - as when a Windows machine is parsing a path is steps through the components one at a time - if a component fails it expects ERRbadpath, not ERRbadfile. */ - if(errno == ENOENT) { - return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND); + if(errno == ENOENT) + { + unix_ERR_class = ERRDOS; + unix_ERR_code = ERRbadpath; } +#if 0 + /* Ugly - NT specific hack - maybe not needed ? (JRA) */ + if((errno == ENOTDIR) && (Protocol >= PROTOCOL_NT1) && + (get_remote_arch() == RA_WINNT)) + { + unix_ERR_class = ERRDOS; + unix_ERR_code = ERRbaddirectory; + } +#endif + return(UNIXERROR(ERRDOS,ERRbadpath)); } @@ -418,11 +1164,9 @@ int reply_getatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size SMB_OFF_T size=0; time_t mtime=0; BOOL bad_path = False; - char *p; START_PROFILE(SMBgetatr); - - p = smb_buf(inbuf) + 1; - p += srvstr_pull(inbuf, fname, p, sizeof(fname), -1, STR_TERMINATE); + + pstrcpy(fname,smb_buf(inbuf) + 1); RESOLVE_DFSPATH(fname, conn, inbuf, outbuf); @@ -477,7 +1221,11 @@ int reply_getatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size SIVAL(outbuf,smb_vwv3,(uint32)size); if (Protocol >= PROTOCOL_NT1) { - SSVAL(outbuf,smb_flg2,SVAL(outbuf, smb_flg2) | 0x40); /* IS_LONG_NAME */ + char *p = strrchr(fname,'/'); + uint16 flg2 = SVAL(outbuf,smb_flg2); + if (!p) p = fname; + if (!is_8_3(fname, True)) + SSVAL(outbuf,smb_flg2,flg2 | 0x40); /* IS_LONG_NAME */ } DEBUG( 3, ( "getatr name=%s mode=%d size=%d\n", fname, mode, (uint32)size ) ); @@ -499,12 +1247,9 @@ int reply_setatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size time_t mtime; SMB_STRUCT_STAT sbuf; BOOL bad_path = False; - char *p; - START_PROFILE(SMBsetatr); - - p = smb_buf(inbuf) + 1; - p += srvstr_pull(inbuf, fname, p, sizeof(fname), -1, STR_TERMINATE); + + pstrcpy(fname,smb_buf(inbuf) + 1); unix_convert(fname,conn,0,&bad_path,&sbuf); mode = SVAL(inbuf,smb_vwv0); @@ -584,7 +1329,7 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size char *p; BOOL ok = False; int status_len; - pstring path; + char *path; char status[21]; int dptr_num= -1; BOOL check_descend = False; @@ -602,28 +1347,26 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size outsize = set_message(outbuf,1,3,True); maxentries = SVAL(inbuf,smb_vwv0); dirtype = SVAL(inbuf,smb_vwv1); - p = smb_buf(inbuf) + 1; - p += srvstr_pull(inbuf, path, p, sizeof(path), -1, STR_TERMINATE); - p++; - status_len = SVAL(p, 0); - p += 2; - + path = smb_buf(inbuf) + 1; + status_len = SVAL(smb_buf(inbuf),3 + strlen(path)); + + RESOLVE_DFSPATH(path, conn, inbuf, outbuf); /* dirtype &= ~aDIR; */ - + if (status_len == 0) { SMB_STRUCT_STAT sbuf; pstring dir2; - pstrcpy(directory,path); - pstrcpy(dir2,path); + pstrcpy(directory,smb_buf(inbuf)+1); + pstrcpy(dir2,smb_buf(inbuf)+1); unix_convert(directory,conn,0,&bad_path,&sbuf); unix_format(dir2); if (!check_name(directory,conn)) can_open = False; - p = strrchr_m(dir2,'/'); + p = strrchr(dir2,'/'); if (p == NULL) { pstrcpy(mask,dir2); @@ -635,7 +1378,7 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size pstrcpy(mask,p+1); } - p = strrchr_m(directory,'/'); + p = strrchr(directory,'/'); if (!p) *directory = 0; else @@ -648,7 +1391,7 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size } else { - memcpy(status,p,21); + memcpy(status,smb_buf(inbuf) + 1 + strlen(path) + 4,21); dirtype = CVAL(status,0) & 0x1F; conn->dirptr = dptr_fetch(status+12,&dptr_num); if (!conn->dirptr) @@ -679,7 +1422,7 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size return (UNIXERROR(ERRDOS,ERRnofids)); } END_PROFILE(SMBsearch); - return ERROR_DOS(ERRDOS,ERRnofids); + return(ERROR(ERRDOS,ERRnofids)); } dptr_set_wcard(dptr_num, strdup(mask)); } @@ -726,11 +1469,11 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size SearchEmpty: - if (numentries == 0 || !ok) + if ( (numentries == 0) || !ok) { - CVAL(outbuf,smb_rcls) = ERRDOS; - SSVAL(outbuf,smb_err,ERRnofiles); - dptr_close(&dptr_num); + CVAL(outbuf,smb_rcls) = ERRDOS; + SSVAL(outbuf,smb_err,ERRnofiles); + dptr_close(&dptr_num); } /* If we were called as SMBffirst with smb_search_id == NULL @@ -755,9 +1498,10 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size SSVAL(smb_buf(outbuf),1,numentries*DIR_STRUCT_SIZE); if (Protocol >= PROTOCOL_NT1) { - SSVAL(outbuf,smb_flg2,SVAL(outbuf, smb_flg2) | 0x40); /* IS_LONG_NAME */ + uint16 flg2 = SVAL(outbuf,smb_flg2); + SSVAL(outbuf,smb_flg2,flg2 | 0x40); /* IS_LONG_NAME */ } - + outsize += DIR_STRUCT_SIZE*numentries; smb_setlen(outbuf,outsize - 4); @@ -780,26 +1524,22 @@ int reply_fclose(connection_struct *conn, char *inbuf,char *outbuf, int dum_size { int outsize = 0; int status_len; - pstring path; + char *path; char status[21]; int dptr_num= -2; - char *p; - START_PROFILE(SMBfclose); outsize = set_message(outbuf,1,0,True); - p = smb_buf(inbuf) + 1; - p += srvstr_pull(inbuf, path, p, sizeof(path), -1, STR_TERMINATE); - p++; - status_len = SVAL(p,0); - p += 2; + path = smb_buf(inbuf) + 1; + status_len = SVAL(smb_buf(inbuf),3 + strlen(path)); + if (status_len == 0) { END_PROFILE(SMBfclose); - return ERROR_DOS(ERRSRV,ERRsrverror); + return(ERROR(ERRSRV,ERRsrverror)); } - memcpy(status,p,21); + memcpy(status,smb_buf(inbuf) + 1 + strlen(path) + 4,21); if(dptr_fetch(status+12,&dptr_num)) { /* Close the dptr - we know it's gone */ @@ -837,7 +1577,7 @@ int reply_open(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, share_mode = SVAL(inbuf,smb_vwv0); - srvstr_pull(inbuf, fname, smb_buf(inbuf)+1, sizeof(fname), -1, STR_TERMINATE); + pstrcpy(fname,smb_buf(inbuf)+1); RESOLVE_DFSPATH(fname, conn, inbuf, outbuf); @@ -867,7 +1607,7 @@ int reply_open(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, DEBUG(3,("attempt to open a directory %s\n",fname)); close_file(fsp,False); END_PROFILE(SMBopen); - return ERROR_DOS(ERRDOS,ERRnoaccess); + return(ERROR(ERRDOS,ERRnoaccess)); } outsize = set_message(outbuf,7,0,True); @@ -926,12 +1666,13 @@ int reply_open_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt return reply_open_pipe_and_X(conn, inbuf,outbuf,length,bufsize); } else { END_PROFILE(SMBopenX); - return ERROR_DOS(ERRSRV,ERRaccess); + return (ERROR(ERRSRV,ERRaccess)); } } /* XXXX we need to handle passed times, sattr and flags */ - srvstr_pull(inbuf, fname, smb_buf(inbuf), sizeof(fname), -1, STR_TERMINATE); + + pstrcpy(fname,smb_buf(inbuf)); RESOLVE_DFSPATH(fname, conn, inbuf, outbuf); @@ -959,7 +1700,7 @@ int reply_open_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt if (fmode & aDIR) { close_file(fsp,False); END_PROFILE(SMBopenX); - return ERROR_DOS(ERRDOS,ERRnoaccess); + return(ERROR(ERRDOS,ERRnoaccess)); } /* If the caller set the extended oplock request bit @@ -1054,7 +1795,7 @@ int reply_mknew(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, com = SVAL(inbuf,smb_com); createmode = SVAL(inbuf,smb_vwv0); - srvstr_pull(inbuf, fname, smb_buf(inbuf) + 1, sizeof(fname), -1, STR_TERMINATE); + pstrcpy(fname,smb_buf(inbuf)+1); RESOLVE_DFSPATH(fname, conn, inbuf, outbuf); @@ -1116,115 +1857,107 @@ int reply_mknew(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, ****************************************************************************/ int reply_ctemp(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize) { - pstring fname; - int outsize = 0; - int createmode; - mode_t unixmode; - BOOL bad_path = False; - files_struct *fsp; - int oplock_request = CORE_OPLOCK_REQUEST(inbuf); - int tmpfd; - SMB_STRUCT_STAT sbuf; - char *p, *s; + pstring fname; + int outsize = 0; + int createmode; + mode_t unixmode; + BOOL bad_path = False; + files_struct *fsp; + int oplock_request = CORE_OPLOCK_REQUEST(inbuf); + int tmpfd; + SMB_STRUCT_STAT sbuf; + char *p, *s; - START_PROFILE(SMBctemp); + START_PROFILE(SMBctemp); - createmode = SVAL(inbuf,smb_vwv0); - srvstr_pull(inbuf, fname, smb_buf(inbuf)+1, sizeof(fname), -1, STR_TERMINATE); - pstrcat(fname,"\\TMXXXXXX"); + createmode = SVAL(inbuf,smb_vwv0); + pstrcpy(fname,smb_buf(inbuf)+1); + pstrcat(fname,"\\TMXXXXXX"); - RESOLVE_DFSPATH(fname, conn, inbuf, outbuf); + RESOLVE_DFSPATH(fname, conn, inbuf, outbuf); - unix_convert(fname,conn,0,&bad_path,&sbuf); - - unixmode = unix_mode(conn,createmode,fname); - - tmpfd = smb_mkstemp(fname); - if (tmpfd == -1) { - END_PROFILE(SMBctemp); - return(UNIXERROR(ERRDOS,ERRnoaccess)); - } + unix_convert(fname,conn,0,&bad_path,&sbuf); - vfs_stat(conn,fname,&sbuf); + unixmode = unix_mode(conn,createmode,fname); - /* Open file in dos compatibility share mode. */ - /* We should fail if file does not exist. */ - fsp = open_file_shared(conn,fname,&sbuf, - SET_DENY_MODE(DENY_FCB)|SET_OPEN_MODE(DOS_OPEN_FCB), - FILE_EXISTS_OPEN|FILE_FAIL_IF_NOT_EXIST, - unixmode, oplock_request, NULL, NULL); + tmpfd = smb_mkstemp(fname); + if (tmpfd == -1) { + END_PROFILE(SMBctemp); + return(UNIXERROR(ERRDOS,ERRnoaccess)); + } - /* close fd from smb_mkstemp() */ - close(tmpfd); + vfs_stat(conn,fname,&sbuf); - if (!fsp) - { - if((errno == ENOENT) && bad_path) - { - unix_ERR_class = ERRDOS; - unix_ERR_code = ERRbadpath; - } - END_PROFILE(SMBctemp); - return(UNIXERROR(ERRDOS,ERRnoaccess)); - } + /* Open file in dos compatibility share mode. */ + /* We should fail if file does not exist. */ + fsp = open_file_shared(conn,fname,&sbuf, + SET_DENY_MODE(DENY_FCB)|SET_OPEN_MODE(DOS_OPEN_FCB), + FILE_EXISTS_OPEN|FILE_FAIL_IF_NOT_EXIST, + unixmode, oplock_request, NULL, NULL); + /* close fd from smb_mkstemp() */ + close(tmpfd); - outsize = set_message(outbuf,1,0,True); - SSVAL(outbuf,smb_vwv0,fsp->fnum); + if (!fsp) { + if((errno == ENOENT) && bad_path) { + unix_ERR_class = ERRDOS; + unix_ERR_code = ERRbadpath; + } + END_PROFILE(SMBctemp); + return(UNIXERROR(ERRDOS,ERRnoaccess)); + } - /* the returned filename is relative to the directory */ - s = strrchr_m(fname, '/'); - if (!s) { - s = fname; - } else { - s++; - } + /* the returned filename is relative to the directory */ + s = strrchr(fname, '/'); + if (!s) + s = fname; + else + s++; - p = smb_buf(outbuf); - SSVALS(p, 0, -1); /* what is this? not in spec */ - SSVAL(p, 2, strlen(s)); - p += 4; - p += srvstr_push(outbuf, p, s, -1, STR_ASCII); - outsize = set_message_end(outbuf, p); + outsize = set_message(outbuf,1,4+ strlen(fname),True); + SSVAL(outbuf,smb_vwv0,fsp->fnum); - if (oplock_request && lp_fake_oplocks(SNUM(conn))) { - CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED; - } + p = smb_buf(outbuf); + SSVALS(p, 0, -1); /* what is this? not in spec */ + SSVAL(p, 2, strlen(s)); + p += 4; + pstrcpy(p,s); + + if (oplock_request && lp_fake_oplocks(SNUM(conn))) { + CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED; + } - if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) - CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED; + if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) + CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED; - DEBUG( 2, ( "created temp file %s\n", fname ) ); - DEBUG( 3, ( "ctemp %s fd=%d dmode=%d umode=%o\n", - fname, fsp->fd, createmode, (int)unixmode ) ); + DEBUG( 2, ( "created temp file %s\n", fname ) ); + DEBUG( 3, ( "ctemp %s fd=%d dmode=%d umode=%o\n", + fname, fsp->fd, createmode, (int)unixmode ) ); - END_PROFILE(SMBctemp); - return(outsize); + END_PROFILE(SMBctemp); + return(outsize); } /******************************************************************* check if a user is allowed to delete a file ********************************************************************/ -static NTSTATUS can_delete(char *fname,connection_struct *conn, int dirtype) +static BOOL can_delete(char *fname,connection_struct *conn, int dirtype) { - SMB_STRUCT_STAT sbuf; - int fmode; - - if (!CAN_WRITE(conn)) return NT_STATUS_MEDIA_WRITE_PROTECTED; - - if (conn->vfs_ops.lstat(conn,fname,&sbuf) != 0) return NT_STATUS_OBJECT_NAME_NOT_FOUND; - - fmode = dos_mode(conn,fname,&sbuf); - if (fmode & aDIR) return NT_STATUS_FILE_IS_A_DIRECTORY; - if (!lp_delete_readonly(SNUM(conn))) { - if (fmode & aRONLY) return NT_STATUS_CANNOT_DELETE; - } - if ((fmode & ~dirtype) & (aHIDDEN | aSYSTEM)) - return NT_STATUS_CANNOT_DELETE; + SMB_STRUCT_STAT sbuf; + int fmode; - if (!check_file_sharing(conn,fname,False)) return NT_STATUS_SHARING_VIOLATION; + if (!CAN_WRITE(conn)) return(False); - return NT_STATUS_OK; + if (conn->vfs_ops.lstat(conn,dos_to_unix(fname,False),&sbuf) != 0) return(False); + fmode = dos_mode(conn,fname,&sbuf); + if (fmode & aDIR) return(False); + if (!lp_delete_readonly(SNUM(conn))) { + if (fmode & aRONLY) return(False); + } + if ((fmode & ~dirtype) & (aHIDDEN | aSYSTEM)) + return(False); + if (!check_file_sharing(conn,fname,False)) return(False); + return(True); } /**************************************************************************** @@ -1232,133 +1965,140 @@ static NTSTATUS can_delete(char *fname,connection_struct *conn, int dirtype) code. ****************************************************************************/ -NTSTATUS unlink_internals(connection_struct *conn, int dirtype, char *name) +int unlink_internals(connection_struct *conn, char *inbuf,char *outbuf, + int dirtype, char *name) { - pstring directory; - pstring mask; - char *p; - int count=0; - NTSTATUS error = NT_STATUS_OK; - BOOL has_wild; - BOOL exists=False; - BOOL bad_path = False; - BOOL rc = True; - SMB_STRUCT_STAT sbuf; - - *directory = *mask = 0; - - rc = unix_convert(name,conn,0,&bad_path,&sbuf); - - p = strrchr_m(name,'/'); - if (!p) { - pstrcpy(directory,"./"); - pstrcpy(mask,name); - } else { - *p = 0; - pstrcpy(directory,name); - pstrcpy(mask,p+1); - } - - /* - * We should only check the mangled cache - * here if unix_convert failed. This means - * that the path in 'mask' doesn't exist - * on the file system and so we need to look - * for a possible mangle. This patch from - * Tine Smukavec <valentin.smukavec@hermes.si>. - */ - - if (!rc && is_mangled(mask)) - check_mangled_cache( mask ); - - has_wild = ms_has_wild(mask); - - if (!has_wild) { - pstrcat(directory,"/"); - pstrcat(directory,mask); - error = can_delete(directory,conn,dirtype); - if (!NT_STATUS_IS_OK(error)) return error; + pstring directory; + pstring mask; + char *p; + int count=0; + int error = ERRnoaccess; + BOOL has_wild; + BOOL exists=False; + BOOL bad_path = False; + BOOL rc = True; + SMB_STRUCT_STAT sbuf; - if (vfs_unlink(conn,directory) == 0) { - count++; - } - if (!count) - exists = vfs_file_exist(conn,directory,&sbuf); - } else { - void *dirptr = NULL; - char *dname; - - if (check_name(directory,conn)) - dirptr = OpenDir(conn, directory, True); - - /* XXXX the CIFS spec says that if bit0 of the flags2 field is set then - the pattern matches against the long name, otherwise the short name - We don't implement this yet XXXX - */ - - if (dirptr) { - error = NT_STATUS_OBJECT_NAME_NOT_FOUND; - - if (strequal(mask,"????????.???")) - pstrcpy(mask,"*"); + *directory = *mask = 0; - while ((dname = ReadDirName(dirptr))) { - pstring fname; - pstrcpy(fname,dname); - - if(!mask_match(fname, mask, case_sensitive)) continue; - - slprintf(fname,sizeof(fname)-1, "%s/%s",directory,dname); - error = can_delete(fname,conn,dirtype); - if (!NT_STATUS_IS_OK(error)) continue; - if (vfs_unlink(conn,fname) == 0) count++; - DEBUG(3,("unlink_internals: succesful unlink [%s]\n",fname)); - } - CloseDir(dirptr); - } - } - - if (count == 0 && NT_STATUS_IS_OK(error)) { - error = map_nt_error_from_unix(errno); - } + rc = unix_convert(name,conn,0,&bad_path,&sbuf); + + p = strrchr(name,'/'); + if (!p) { + pstrcpy(directory,"./"); + pstrcpy(mask,name); + } else { + *p = 0; + pstrcpy(directory,name); + pstrcpy(mask,p+1); + } + + /* + * We should only check the mangled cache + * here if unix_convert failed. This means + * that the path in 'mask' doesn't exist + * on the file system and so we need to look + * for a possible mangle. This patch from + * Tine Smukavec <valentin.smukavec@hermes.si>. + */ + + if (!rc && is_mangled(mask)) + check_mangled_cache( mask ); + + has_wild = ms_has_wild(mask); + + if (!has_wild) { + pstrcat(directory,"/"); + pstrcat(directory,mask); + if (can_delete(directory,conn,dirtype) && !vfs_unlink(conn,directory)) + count++; + if (!count) + exists = vfs_file_exist(conn,directory,&sbuf); + } else { + void *dirptr = NULL; + char *dname; + + if (check_name(directory,conn)) + dirptr = OpenDir(conn, directory, True); + + /* XXXX the CIFS spec says that if bit0 of the flags2 field is set then + the pattern matches against the long name, otherwise the short name + We don't implement this yet XXXX + */ + + if (dirptr) + { + error = ERRbadfile; - return error; + if (strequal(mask,"????????.???")) + pstrcpy(mask,"*"); + + while ((dname = ReadDirName(dirptr))) + { + pstring fname; + pstrcpy(fname,dname); + + if(!mask_match(fname, mask, case_sensitive)) continue; + + error = ERRnoaccess; + slprintf(fname,sizeof(fname)-1, "%s/%s",directory,dname); + if (!can_delete(fname,conn,dirtype)) continue; + if (!vfs_unlink(conn,fname)) count++; + DEBUG(3,("unlink_internals: succesful unlink [%s]\n",fname)); + } + CloseDir(dirptr); + } + } + + if (count == 0) { + if (exists) + return(ERROR(ERRDOS,error)); + else { + if((errno == ENOENT) && bad_path) { + unix_ERR_class = ERRDOS; + unix_ERR_code = ERRbadpath; + } + return(UNIXERROR(ERRDOS,error)); + } + } + + return 0; } /**************************************************************************** Reply to a unlink ****************************************************************************/ -int reply_unlink(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, - int dum_buffsize) +int reply_unlink(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize) { - int outsize = 0; - pstring name; - int dirtype; - NTSTATUS status; - START_PROFILE(SMBunlink); - - dirtype = SVAL(inbuf,smb_vwv0); - - srvstr_pull(inbuf, name, smb_buf(inbuf) + 1, sizeof(name), -1, STR_TERMINATE); - - RESOLVE_DFSPATH(name, conn, inbuf, outbuf); - - DEBUG(3,("reply_unlink : %s\n",name)); - - status = unlink_internals(conn, dirtype, name); - if (!NT_STATUS_IS_OK(status)) return ERROR_NT(status); + int outsize = 0; + pstring name; + int dirtype; + START_PROFILE(SMBunlink); - /* - * Win2k needs a changenotify request response before it will - * update after a rename.. - */ - process_pending_change_notify_queue((time_t)0); - - outsize = set_message(outbuf,0,0,True); + dirtype = SVAL(inbuf,smb_vwv0); + + pstrcpy(name,smb_buf(inbuf) + 1); + + RESOLVE_DFSPATH(name, conn, inbuf, outbuf); + + DEBUG(3,("reply_unlink : %s\n",name)); + + outsize = unlink_internals(conn, inbuf, outbuf, dirtype, name); + if(outsize == 0) { + + /* + * Win2k needs a changenotify request response before it will + * update after a rename.. + */ + + process_pending_change_notify_queue((time_t)0); + + outsize = set_message(outbuf,0,0,True); + } - END_PROFILE(SMBunlink); - return outsize; + END_PROFILE(SMBunlink); + return(outsize); } /**************************************************************************** @@ -1502,74 +2242,73 @@ int reply_readbraw(connection_struct *conn, char *inbuf, char *outbuf, int dum_s return -1; } + /**************************************************************************** reply to a lockread (core+ protocol) ****************************************************************************/ int reply_lockread(connection_struct *conn, char *inbuf,char *outbuf, int length, int dum_buffsiz) { - ssize_t nread = -1; - char *data; - int outsize = 0; - SMB_OFF_T startpos; - size_t numtoread; - NTSTATUS status; - files_struct *fsp = file_fsp(inbuf,smb_vwv0); - START_PROFILE(SMBlockread); + ssize_t nread = -1; + char *data; + int outsize = 0; + SMB_OFF_T startpos; + size_t numtoread; + int eclass; + uint32 ecode; + files_struct *fsp = file_fsp(inbuf,smb_vwv0); + START_PROFILE(SMBlockread); - CHECK_FSP(fsp,conn); - CHECK_READ(fsp); + CHECK_FSP(fsp,conn); + CHECK_READ(fsp); - release_level_2_oplocks_on_change(fsp); + release_level_2_oplocks_on_change(fsp); - numtoread = SVAL(inbuf,smb_vwv1); - startpos = IVAL(inbuf,smb_vwv2); + numtoread = SVAL(inbuf,smb_vwv1); + startpos = IVAL(inbuf,smb_vwv2); - outsize = set_message(outbuf,5,3,True); - numtoread = MIN(BUFFER_SIZE-outsize,numtoread); - data = smb_buf(outbuf) + 3; - - /* - * NB. Discovered by Menny Hamburger at Mainsoft. This is a core+ - * protocol request that predates the read/write lock concept. - * Thus instead of asking for a read lock here we need to ask - * for a write lock. JRA. - */ - - status = do_lock(fsp, conn, SVAL(inbuf,smb_pid), - (SMB_BIG_UINT)numtoread, (SMB_BIG_UINT)startpos, WRITE_LOCK); + outsize = set_message(outbuf,5,3,True); + numtoread = MIN(BUFFER_SIZE-outsize,numtoread); + data = smb_buf(outbuf) + 3; + + /* + * NB. Discovered by Menny Hamburger at Mainsoft. This is a core+ + * protocol request that predates the read/write lock concept. + * Thus instead of asking for a read lock here we need to ask + * for a write lock. JRA. + */ - if (NT_STATUS_V(status)) { - if (lp_blocking_locks(SNUM(conn))) { - /* - * A blocking lock was requested. Package up - * this smb into a queued request and push it - * onto the blocking lock queue. - */ - if(push_blocking_lock_request(inbuf, length, -1, 0)) - END_PROFILE(SMBlockread); - return -1; - } + if(!do_lock( fsp, conn, SVAL(inbuf,smb_pid), (SMB_BIG_UINT)numtoread, (SMB_BIG_UINT)startpos, WRITE_LOCK, &eclass, &ecode)) { + if((ecode == ERRlock) && lp_blocking_locks(SNUM(conn))) { + /* + * A blocking lock was requested. Package up + * this smb into a queued request and push it + * onto the blocking lock queue. + */ + if(push_blocking_lock_request(inbuf, length, -1, 0)) END_PROFILE(SMBlockread); - return ERROR_NT(status); - } + return -1; + } + END_PROFILE(SMBlockread); + return (ERROR(eclass,ecode)); + } - nread = read_file(fsp,data,startpos,numtoread); + nread = read_file(fsp,data,startpos,numtoread); - if (nread < 0) { - END_PROFILE(SMBlockread); - return(UNIXERROR(ERRDOS,ERRnoaccess)); - } - - outsize += nread; - SSVAL(outbuf,smb_vwv0,nread); - SSVAL(outbuf,smb_vwv5,nread+3); - SSVAL(smb_buf(outbuf),1,nread); - - DEBUG(3,("lockread fnum=%d num=%d nread=%d\n", - fsp->fnum, (int)numtoread, (int)nread)); + if (nread < 0) { + END_PROFILE(SMBlockread); + return(UNIXERROR(ERRDOS,ERRnoaccess)); + } - END_PROFILE(SMBlockread); - return(outsize); + outsize += nread; + SSVAL(outbuf,smb_vwv0,nread); + SSVAL(outbuf,smb_vwv5,nread+3); + SSVAL(smb_buf(outbuf),1,nread); + + DEBUG( 3, ( "lockread fnum=%d num=%d nread=%d\n", + fsp->fnum, (int)numtoread, (int)nread ) ); + + END_PROFILE(SMBlockread); + return(outsize); } @@ -1592,20 +2331,19 @@ int reply_read(connection_struct *conn, char *inbuf,char *outbuf, int size, int numtoread = SVAL(inbuf,smb_vwv1); startpos = IVAL(inbuf,smb_vwv2); - - + outsize = set_message(outbuf,5,3,True); numtoread = MIN(BUFFER_SIZE-outsize,numtoread); data = smb_buf(outbuf) + 3; if (is_locked(fsp,conn,(SMB_BIG_UINT)numtoread,(SMB_BIG_UINT)startpos, READ_LOCK,False)) { END_PROFILE(SMBread); - return ERROR_DOS(ERRDOS,ERRlock); + return(ERROR(ERRDOS,ERRlock)); } if (numtoread > 0) nread = read_file(fsp,data,startpos,numtoread); - + if (nread < 0) { END_PROFILE(SMBread); return(UNIXERROR(ERRDOS,ERRnoaccess)); @@ -1667,7 +2405,7 @@ int reply_read_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt DEBUG(0,("reply_read_and_X - large offset (%x << 32) used and we don't support \ 64 bit offsets.\n", (unsigned int)IVAL(inbuf,smb_vwv10) )); END_PROFILE(SMBreadX); - return ERROR_DOS(ERRDOS,ERRbadaccess); + return(ERROR(ERRDOS,ERRbadaccess)); } #endif /* LARGE_SMB_OFF_T */ @@ -1676,10 +2414,10 @@ int reply_read_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt if (is_locked(fsp,conn,(SMB_BIG_UINT)smb_maxcnt,(SMB_BIG_UINT)startpos, READ_LOCK,False)) { END_PROFILE(SMBreadX); - return ERROR_DOS(ERRDOS,ERRlock); + return(ERROR(ERRDOS,ERRlock)); } nread = read_file(fsp,data,startpos,smb_maxcnt); - + if (nread < 0) { END_PROFILE(SMBreadX); return(UNIXERROR(ERRDOS,ERRnoaccess)); @@ -1737,7 +2475,7 @@ int reply_writebraw(connection_struct *conn, char *inbuf,char *outbuf, int size, if (is_locked(fsp,conn,(SMB_BIG_UINT)tcount,(SMB_BIG_UINT)startpos, WRITE_LOCK,False)) { END_PROFILE(SMBwritebraw); - return(ERROR_DOS(ERRDOS,ERRlock)); + return(ERROR(ERRDOS,ERRlock)); } if (numtowrite>0) @@ -1828,65 +2566,83 @@ int reply_writebraw(connection_struct *conn, char *inbuf,char *outbuf, int size, reply to a writeunlock (core+) ****************************************************************************/ -int reply_writeunlock(connection_struct *conn, char *inbuf,char *outbuf, - int size, int dum_buffsize) +int reply_writeunlock(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize) { - ssize_t nwritten = -1; - size_t numtowrite; - SMB_OFF_T startpos; - char *data; - NTSTATUS status; - files_struct *fsp = file_fsp(inbuf,smb_vwv0); - int outsize = 0; - START_PROFILE(SMBwriteunlock); - - CHECK_FSP(fsp,conn); - CHECK_WRITE(fsp); + ssize_t nwritten = -1; + size_t numtowrite; + SMB_OFF_T startpos; + char *data; + int eclass; + uint32 ecode; + files_struct *fsp = file_fsp(inbuf,smb_vwv0); + int outsize = 0; + START_PROFILE(SMBwriteunlock); - numtowrite = SVAL(inbuf,smb_vwv1); - startpos = IVAL(inbuf,smb_vwv2); - data = smb_buf(inbuf) + 3; + CHECK_FSP(fsp,conn); + CHECK_WRITE(fsp); + + numtowrite = SVAL(inbuf,smb_vwv1); + startpos = IVAL(inbuf,smb_vwv2); + data = smb_buf(inbuf) + 3; - if (is_locked(fsp,conn,(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, - WRITE_LOCK,False)) { - END_PROFILE(SMBwriteunlock); - return ERROR_DOS(ERRDOS,ERRlock); - } + if (is_locked(fsp,conn,(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, WRITE_LOCK,False)) { + END_PROFILE(SMBwriteunlock); + return(ERROR(ERRDOS,ERRlock)); + } - /* The special X/Open SMB protocol handling of - zero length writes is *NOT* done for - this call */ - if(numtowrite == 0) - nwritten = 0; - else - nwritten = write_file(fsp,data,startpos,numtowrite); + /* The special X/Open SMB protocol handling of + zero length writes is *NOT* done for + this call */ + if(numtowrite == 0) + nwritten = 0; + else + nwritten = write_file(fsp,data,startpos,numtowrite); - if (lp_syncalways(SNUM(conn))) - sync_file(conn,fsp); + if (lp_syncalways(SNUM(conn))) + sync_file(conn,fsp); - if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) { - END_PROFILE(SMBwriteunlock); - return(UNIXERROR(ERRDOS,ERRnoaccess)); - } + if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) { + END_PROFILE(SMBwriteunlock); + return(UNIXERROR(ERRDOS,ERRnoaccess)); + } - status = do_unlock(fsp, conn, SVAL(inbuf,smb_pid), (SMB_BIG_UINT)numtowrite, - (SMB_BIG_UINT)startpos); - if (NT_STATUS_V(status)) { - END_PROFILE(SMBwriteunlock); - return ERROR_NT(status); - } - - outsize = set_message(outbuf,1,0,True); - - SSVAL(outbuf,smb_vwv0,nwritten); - - DEBUG(3,("writeunlock fnum=%d num=%d wrote=%d\n", - fsp->fnum, (int)numtowrite, (int)nwritten)); - - END_PROFILE(SMBwriteunlock); - return outsize; + if(!do_unlock(fsp, conn, SVAL(inbuf,smb_pid), (SMB_BIG_UINT)numtowrite, (SMB_BIG_UINT)startpos, &eclass, &ecode)) { + END_PROFILE(SMBwriteunlock); + return(ERROR(eclass,ecode)); + } + + outsize = set_message(outbuf,1,0,True); + + SSVAL(outbuf,smb_vwv0,nwritten); + + DEBUG( 3, ( "writeunlock fnum=%d num=%d wrote=%d\n", + fsp->fnum, (int)numtowrite, (int)nwritten ) ); + + END_PROFILE(SMBwriteunlock); + return(outsize); } +/**************************************************************************** + Return correct error for space allocation fail. +****************************************************************************/ + +int allocate_space_error(char *inbuf,char *outbuf, int errno_val) +{ + errno = errno_val; + if (!(global_client_caps & CAP_STATUS32)) + return (UNIXERROR(ERRHRD,ERRdiskfull)); + + /* Use more specific WNT/W2K error codes. */ +#ifdef EDQUOT + if (errno_val == ENOSPC || errno_val == EDQUOT) { +#else + if (errno_val == ENOSPC) { +#endif + return(ERROR(0,NT_STATUS_DISK_FULL)); + } + + return (UNIXERROR(ERRHRD,ERRdiskfull)); +} /**************************************************************************** Reply to a write. @@ -1917,7 +2673,7 @@ int reply_write(connection_struct *conn, char *inbuf,char *outbuf,int size,int d if (is_locked(fsp,conn,(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, WRITE_LOCK,False)) { END_PROFILE(SMBwrite); - return ERROR_DOS(ERRDOS,ERRlock); + return(ERROR(ERRDOS,ERRlock)); } /* X/Open SMB protocol says that if smb_vwv1 is @@ -1927,8 +2683,9 @@ int reply_write(connection_struct *conn, char *inbuf,char *outbuf,int size,int d /* This is actually an allocate call, not set EOF. JRA */ nwritten = vfs_allocate_file_space(fsp, (SMB_OFF_T)startpos); if (nwritten < 0) { - END_PROFILE(SMBwrite); - return ERROR_NT(NT_STATUS_DISK_FULL); + int ret = allocate_space_error(inbuf, outbuf, errno); + END_PROFILE(SMBwrite); + return ret; } } else nwritten = write_file(fsp,data,startpos,numtowrite); @@ -1989,7 +2746,7 @@ int reply_write_and_X(connection_struct *conn, char *inbuf,char *outbuf,int leng if(smb_doff > smblen || (smb_doff + numtowrite > smblen)) { END_PROFILE(SMBwriteX); - return ERROR_DOS(ERRDOS,ERRbadmem); + return(ERROR(ERRDOS,ERRbadmem)); } data = smb_base(inbuf) + smb_doff; @@ -2011,7 +2768,7 @@ int reply_write_and_X(connection_struct *conn, char *inbuf,char *outbuf,int leng DEBUG(0,("reply_write_and_X - large offset (%x << 32) used and we don't support \ 64 bit offsets.\n", (unsigned int)IVAL(inbuf,smb_vwv12) )); END_PROFILE(SMBwriteX); - return ERROR_DOS(ERRDOS,ERRbadaccess); + return(ERROR(ERRDOS,ERRbadaccess)); } #endif /* LARGE_SMB_OFF_T */ @@ -2019,7 +2776,7 @@ int reply_write_and_X(connection_struct *conn, char *inbuf,char *outbuf,int leng if (is_locked(fsp,conn,(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, WRITE_LOCK,False)) { END_PROFILE(SMBwriteX); - return ERROR_DOS(ERRDOS,ERRlock); + return(ERROR(ERRDOS,ERRlock)); } /* X/Open SMB protocol says that, unlike SMBwrite @@ -2140,7 +2897,7 @@ int reply_lseek(connection_struct *conn, char *inbuf,char *outbuf, int size, int } /**************************************************************************** - reply to a flush + Reply to a flush. ****************************************************************************/ int reply_flush(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize) @@ -2150,19 +2907,18 @@ int reply_flush(connection_struct *conn, char *inbuf,char *outbuf, int size, int START_PROFILE(SMBflush); CHECK_FSP(fsp,conn); - + if (!fsp) { file_sync_all(conn); } else { sync_file(conn,fsp); } - + DEBUG(3,("flush\n")); END_PROFILE(SMBflush); return(outsize); } - /**************************************************************************** reply to a exit ****************************************************************************/ @@ -2188,7 +2944,6 @@ int reply_close(connection_struct *conn, char *inbuf,char *outbuf, int size, { int outsize = 0; time_t mtime; - int32 eclass = 0, err = 0; files_struct *fsp = NULL; START_PROFILE(SMBclose); @@ -2208,7 +2963,7 @@ int reply_close(connection_struct *conn, char *inbuf,char *outbuf, int size, if(!fsp || (fsp->conn != conn)) { END_PROFILE(SMBclose); - return ERROR_DOS(ERRDOS,ERRbadfid); + return(ERROR(ERRDOS,ERRbadfid)); } if(fsp->is_directory || fsp->stat_open) { @@ -2256,12 +3011,6 @@ int reply_close(connection_struct *conn, char *inbuf,char *outbuf, int size, } } - /* We have a cached error */ - if(eclass || err) { - END_PROFILE(SMBclose); - return ERROR_DOS(eclass,err); - } - END_PROFILE(SMBclose); return(outsize); } @@ -2294,7 +3043,7 @@ int reply_writeclose(connection_struct *conn, if (is_locked(fsp,conn,(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, WRITE_LOCK,False)) { END_PROFILE(SMBwriteclose); - return ERROR_DOS(ERRDOS,ERRlock); + return(ERROR(ERRDOS,ERRlock)); } nwritten = write_file(fsp,data,startpos,numtowrite); @@ -2334,7 +3083,8 @@ int reply_lock(connection_struct *conn, { int outsize = set_message(outbuf,0,0,True); SMB_BIG_UINT count,offset; - NTSTATUS status; + int eclass; + uint32 ecode; files_struct *fsp = file_fsp(inbuf,smb_vwv0); START_PROFILE(SMBlock); @@ -2348,21 +3098,20 @@ int reply_lock(connection_struct *conn, DEBUG(3,("lock fd=%d fnum=%d offset=%.0f count=%.0f\n", fsp->fd, fsp->fnum, (double)offset, (double)count)); - status = do_lock(fsp, conn, SVAL(inbuf,smb_pid), count, offset, WRITE_LOCK); - if (NT_STATUS_V(status)) { - if (lp_blocking_locks(SNUM(conn))) { - /* - * A blocking lock was requested. Package up - * this smb into a queued request and push it - * onto the blocking lock queue. - */ - if(push_blocking_lock_request(inbuf, length, -1, 0)) { - END_PROFILE(SMBlock); - return -1; - } - } - END_PROFILE(SMBlock); - return ERROR_NT(status); + if (!do_lock(fsp, conn, SVAL(inbuf,smb_pid), count, offset, WRITE_LOCK, &eclass, &ecode)) { + if((ecode == ERRlock) && lp_blocking_locks(SNUM(conn))) { + /* + * A blocking lock was requested. Package up + * this smb into a queued request and push it + * onto the blocking lock queue. + */ + if(push_blocking_lock_request(inbuf, length, -1, 0)) { + END_PROFILE(SMBlock); + return -1; + } + } + END_PROFILE(SMBlock); + return (ERROR(eclass,ecode)); } END_PROFILE(SMBlock); @@ -2373,31 +3122,30 @@ int reply_lock(connection_struct *conn, /**************************************************************************** reply to a unlock ****************************************************************************/ -int reply_unlock(connection_struct *conn, char *inbuf,char *outbuf, int size, - int dum_buffsize) +int reply_unlock(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize) { - int outsize = set_message(outbuf,0,0,True); - SMB_BIG_UINT count,offset; - NTSTATUS status; - files_struct *fsp = file_fsp(inbuf,smb_vwv0); - START_PROFILE(SMBunlock); + int outsize = set_message(outbuf,0,0,True); + SMB_BIG_UINT count,offset; + int eclass; + uint32 ecode; + files_struct *fsp = file_fsp(inbuf,smb_vwv0); + START_PROFILE(SMBunlock); - CHECK_FSP(fsp,conn); - - count = (SMB_BIG_UINT)IVAL(inbuf,smb_vwv1); - offset = (SMB_BIG_UINT)IVAL(inbuf,smb_vwv3); - - status = do_unlock(fsp, conn, SVAL(inbuf,smb_pid), count, offset); - if (NT_STATUS_V(status)) { - END_PROFILE(SMBunlock); - return ERROR_NT(status); - } + CHECK_FSP(fsp,conn); - DEBUG( 3, ( "unlock fd=%d fnum=%d offset=%.0f count=%.0f\n", - fsp->fd, fsp->fnum, (double)offset, (double)count ) ); - - END_PROFILE(SMBunlock); - return(outsize); + count = (SMB_BIG_UINT)IVAL(inbuf,smb_vwv1); + offset = (SMB_BIG_UINT)IVAL(inbuf,smb_vwv3); + + if(!do_unlock(fsp, conn, SVAL(inbuf,smb_pid), count, offset, &eclass, &ecode)) { + END_PROFILE(SMBunlock); + return (ERROR(eclass,ecode)); + } + + DEBUG( 3, ( "unlock fd=%d fnum=%d offset=%.0f count=%.0f\n", + fsp->fd, fsp->fnum, (double)offset, (double)count ) ); + + END_PROFILE(SMBunlock); + return(outsize); } @@ -2416,7 +3164,7 @@ int reply_tdis(connection_struct *conn, if (!conn) { DEBUG(4,("Invalid connection in tdis\n")); END_PROFILE(SMBtdis); - return ERROR_DOS(ERRSRV,ERRinvnid); + return(ERROR(ERRSRV,ERRinvnid)); } conn->used = False; @@ -2482,7 +3230,7 @@ int reply_printopen(connection_struct *conn, if (!CAN_PRINT(conn)) { END_PROFILE(SMBsplopen); - return ERROR_DOS(ERRDOS,ERRnoaccess); + return(ERROR(ERRDOS,ERRnoaccess)); } /* Open for exclusive use, write only. */ @@ -2519,7 +3267,7 @@ int reply_printclose(connection_struct *conn, if (!CAN_PRINT(conn)) { END_PROFILE(SMBsplclose); - return ERROR_DOS(ERRDOS,ERRnoaccess); + return(ERROR(ERRDOS,ERRnoaccess)); } DEBUG(3,("printclose fd=%d fnum=%d\n", @@ -2555,7 +3303,7 @@ int reply_printqueue(connection_struct *conn, get it right (tridge) */ if (!CAN_PRINT(conn)) { END_PROFILE(SMBsplretq); - return ERROR_DOS(ERRDOS,ERRnoaccess); + return(ERROR(ERRDOS,ERRnoaccess)); } SSVAL(outbuf,smb_vwv0,0); @@ -2586,7 +3334,7 @@ int reply_printqueue(connection_struct *conn, SSVAL(p,5, queue[i].job); SIVAL(p,7,queue[i].size); CVAL(p,11) = 0; - srvstr_push(outbuf, p+12, queue[i].user, 16, STR_ASCII); + StrnCpy(p+12,queue[i].user,16); p += 28; } @@ -2598,7 +3346,7 @@ int reply_printqueue(connection_struct *conn, SSVAL(smb_buf(outbuf),1,28*count); } - SAFE_FREE(queue); + if (queue) free(queue); DEBUG(3,("%d entries returned in queue\n",count)); } @@ -2621,7 +3369,7 @@ int reply_printwrite(connection_struct *conn, char *inbuf,char *outbuf, int dum_ if (!CAN_PRINT(conn)) { END_PROFILE(SMBsplwr); - return ERROR_DOS(ERRDOS,ERRnoaccess); + return(ERROR(ERRDOS,ERRnoaccess)); } CHECK_FSP(fsp,conn); @@ -2646,41 +3394,45 @@ int reply_printwrite(connection_struct *conn, char *inbuf,char *outbuf, int dum_ The guts of the mkdir command, split out so it may be called by the NT SMB code. ****************************************************************************/ -NTSTATUS mkdir_internal(connection_struct *conn, pstring directory) +int mkdir_internal(connection_struct *conn, char *inbuf, char *outbuf, pstring directory) { - BOOL bad_path = False; - SMB_STRUCT_STAT sbuf; - int ret= -1; - - unix_convert(directory,conn,0,&bad_path,&sbuf); - - if (check_name(directory, conn)) - ret = vfs_mkdir(conn,directory,unix_mode(conn,aDIR,directory)); - - if (ret == -1) { - return map_nt_error_from_unix(errno); - } - - return NT_STATUS_OK; + BOOL bad_path = False; + SMB_STRUCT_STAT sbuf; + int ret= -1; + + unix_convert(directory,conn,0,&bad_path,&sbuf); + + if (check_name(directory, conn)) + ret = vfs_mkdir(conn,directory,unix_mode(conn,aDIR,directory)); + + if (ret < 0) + { + if((errno == ENOENT) && bad_path) + { + unix_ERR_class = ERRDOS; + unix_ERR_code = ERRbadpath; + } + return(UNIXERROR(ERRDOS,ERRnoaccess)); + } + + return ret; } /**************************************************************************** - Reply to a mkdir. + Reply to a mkdir ****************************************************************************/ int reply_mkdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize) { pstring directory; int outsize; - NTSTATUS status; START_PROFILE(SMBmkdir); - srvstr_pull(inbuf, directory, smb_buf(inbuf) + 1, sizeof(directory), -1, STR_TERMINATE); + pstrcpy(directory,smb_buf(inbuf) + 1); - status = mkdir_internal(conn, directory); - if (!NT_STATUS_IS_OK(status)) return ERROR_NT(status); - - outsize = set_message(outbuf,0,0,True); + outsize=mkdir_internal(conn, inbuf, outbuf, directory); + if(outsize == 0) + outsize = set_message(outbuf,0,0,True); DEBUG( 3, ( "mkdir %s ret=%d\n", directory, outsize ) ); @@ -2720,7 +3472,7 @@ static BOOL recursive_rmdir(connection_struct *conn, char *directory) pstrcat(fullname, "/"); pstrcat(fullname, dname); - if(conn->vfs_ops.lstat(conn,fullname, &st) != 0) { + if(conn->vfs_ops.lstat(conn,dos_to_unix(fullname,False), &st) != 0) { ret = True; break; } @@ -2739,6 +3491,7 @@ static BOOL recursive_rmdir(connection_struct *conn, char *directory) break; } } + CloseDir(dirptr); return ret; } @@ -2773,7 +3526,6 @@ BOOL rmdir_internals(connection_struct *conn, char *directory) break; } } - if(all_veto_files) { SeekDir(dirptr,dirpos); while ((dname = ReadDirName(dirptr))) { @@ -2788,12 +3540,11 @@ BOOL rmdir_internals(connection_struct *conn, char *directory) errno = ENOMEM; break; } - pstrcpy(fullname, directory); pstrcat(fullname, "/"); pstrcat(fullname, dname); - if(conn->vfs_ops.lstat(conn,fullname, &st) != 0) + if(conn->vfs_ops.lstat(conn,dos_to_unix(fullname, False), &st) != 0) break; if(st.st_mode & S_IFDIR) { if(lp_recursive_veto_delete(SNUM(conn))) { @@ -2815,7 +3566,7 @@ BOOL rmdir_internals(connection_struct *conn, char *directory) errno = ENOTEMPTY; } } - + if (!ok) DEBUG(3,("rmdir_internals: couldn't remove directory %s : %s\n", directory,strerror(errno))); @@ -2835,7 +3586,7 @@ int reply_rmdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, SMB_STRUCT_STAT sbuf; START_PROFILE(SMBrmdir); - srvstr_pull(inbuf, directory, smb_buf(inbuf) + 1, sizeof(directory), -1, STR_TERMINATE); + pstrcpy(directory,smb_buf(inbuf) + 1); RESOLVE_DFSPATH(directory, conn, inbuf, outbuf) @@ -2876,21 +3627,21 @@ static BOOL resolve_wildcards(char *name1,char *name2) fstring ext1,ext2; char *p,*p2; - name1 = strrchr_m(name1,'/'); - name2 = strrchr_m(name2,'/'); + name1 = strrchr(name1,'/'); + name2 = strrchr(name2,'/'); if (!name1 || !name2) return(False); fstrcpy(root1,name1); fstrcpy(root2,name2); - p = strrchr_m(root1,'.'); + p = strrchr(root1,'.'); if (p) { *p = 0; fstrcpy(ext1,p+1); } else { fstrcpy(ext1,""); } - p = strrchr_m(root2,'.'); + p = strrchr(root2,'.'); if (p) { *p = 0; fstrcpy(ext2,p+1); @@ -2940,7 +3691,7 @@ static BOOL can_rename(char *fname,connection_struct *conn) if (!CAN_WRITE(conn)) return(False); - if (conn->vfs_ops.lstat(conn,fname,&sbuf) != 0) return(False); + if (conn->vfs_ops.lstat(conn,dos_to_unix(fname,False),&sbuf) != 0) return(False); if (!check_file_sharing(conn,fname,True)) return(False); return(True); } @@ -2949,9 +3700,9 @@ static BOOL can_rename(char *fname,connection_struct *conn) The guts of the rename command, split out so it may be called by the NT SMB code. ****************************************************************************/ -NTSTATUS rename_internals(connection_struct *conn, - char *name, - char *newname, BOOL replace_if_exists) +int rename_internals(connection_struct *conn, + char *inbuf, char *outbuf, char *name, + char *newname, BOOL replace_if_exists) { pstring directory; pstring mask; @@ -2961,10 +3712,11 @@ NTSTATUS rename_internals(connection_struct *conn, BOOL bad_path1 = False; BOOL bad_path2 = False; int count=0; - NTSTATUS error = NT_STATUS_OK; + int error = ERRnoaccess; BOOL exists=False; BOOL rc = True; SMB_STRUCT_STAT sbuf1, sbuf2; + pstring zdirectory; *directory = *mask = 0; @@ -2980,7 +3732,7 @@ NTSTATUS rename_internals(connection_struct *conn, * as this is checked in resolve_wildcards(). */ - p = strrchr_m(name,'/'); + p = strrchr(name,'/'); if (!p) { pstrcpy(directory,"."); pstrcpy(mask,name); @@ -3016,7 +3768,7 @@ NTSTATUS rename_internals(connection_struct *conn, pstrcat(directory,mask); /* Ensure newname contains a '/' also */ - if(strrchr_m(newname,'/') == 0) { + if(strrchr(newname,'/') == 0) { pstring tmpstr; pstrcpy(tmpstr, "./"); @@ -3049,7 +3801,7 @@ NTSTATUS rename_internals(connection_struct *conn, * Note that we guarantee that newname contains a '/' * character above. */ - p = strrchr_m(newname,'/'); + p = strrchr(newname,'/'); pstrcpy(newname_modified_last_component,p+1); if(strcsequal(newname_modified_last_component, @@ -3062,6 +3814,7 @@ NTSTATUS rename_internals(connection_struct *conn, } } + pstrcpy(zdirectory, dos_to_unix(directory, False)); if(replace_if_exists) { /* * NT SMB specific flag - rename can overwrite @@ -3071,13 +3824,15 @@ NTSTATUS rename_internals(connection_struct *conn, if(resolve_wildcards(directory,newname) && can_rename(directory,conn) && - conn->vfs_ops.rename(conn,directory,newname) == 0) + !conn->vfs_ops.rename(conn,zdirectory, + dos_to_unix(newname,False))) count++; } else { if (resolve_wildcards(directory,newname) && can_rename(directory,conn) && !vfs_file_exist(conn,newname,NULL) && - conn->vfs_ops.rename(conn,directory,newname) == 0) + !conn->vfs_ops.rename(conn,zdirectory, + dos_to_unix(newname,False))) count++; } @@ -3087,7 +3842,7 @@ NTSTATUS rename_internals(connection_struct *conn, if (!count) exists = vfs_file_exist(conn,directory,NULL); if (!count && exists && vfs_file_exist(conn,newname,NULL)) { exists = True; - error = NT_STATUS_OBJECT_NAME_COLLISION; + error = ERRrename; } } else { /* @@ -3101,7 +3856,7 @@ NTSTATUS rename_internals(connection_struct *conn, dirptr = OpenDir(conn, directory, True); if (dirptr) { - error = NT_STATUS_OBJECT_NAME_NOT_FOUND; + error = ERRbadfile; if (strequal(mask,"????????.???")) pstrcpy(mask,"*"); @@ -3114,7 +3869,7 @@ NTSTATUS rename_internals(connection_struct *conn, if(!mask_match(fname, mask, case_sensitive)) continue; - error = NT_STATUS_ACCESS_DENIED; + error = ERRnoaccess; slprintf(fname,sizeof(fname)-1,"%s/%s",directory,dname); if (!can_rename(fname,conn)) { DEBUG(6,("rename %s refused\n", fname)); @@ -3131,11 +3886,12 @@ NTSTATUS rename_internals(connection_struct *conn, if (!replace_if_exists && vfs_file_exist(conn,destname, NULL)) { DEBUG(6,("file_exist %s\n", destname)); - error = NT_STATUS_OBJECT_NAME_COLLISION; + error = 183; continue; } - if (!conn->vfs_ops.rename(conn,fname,destname)) + if (!conn->vfs_ops.rename(conn,dos_to_unix(fname,False), + dos_to_unix(destname,False))) count++; DEBUG(3,("rename_internals: doing rename on %s -> %s\n",fname,destname)); } @@ -3143,52 +3899,55 @@ NTSTATUS rename_internals(connection_struct *conn, } } - if (count == 0 && NT_STATUS_IS_OK(error)) { - error = map_nt_error_from_unix(errno); + if (count == 0) { + if (exists) + return(ERROR(ERRDOS,error)); + else { + if((errno == ENOENT) && (bad_path1 || bad_path2)) { + unix_ERR_class = ERRDOS; + unix_ERR_code = ERRbadpath; + } + return(UNIXERROR(ERRDOS,error)); + } } - return error; + return 0; } /**************************************************************************** Reply to a mv. ****************************************************************************/ -int reply_mv(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, - int dum_buffsize) +int reply_mv(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize) { - int outsize = 0; - pstring name; - pstring newname; - char *p; - NTSTATUS status; + int outsize = 0; + pstring name; + pstring newname; + START_PROFILE(SMBmv); - START_PROFILE(SMBmv); + pstrcpy(name,smb_buf(inbuf) + 1); + pstrcpy(newname,smb_buf(inbuf) + 3 + strlen(name)); - p = smb_buf(inbuf) + 1; - p += srvstr_pull(inbuf, name, p, sizeof(name), -1, STR_TERMINATE); - p++; - p += srvstr_pull(inbuf, newname, p, sizeof(newname), -1, STR_TERMINATE); - - RESOLVE_DFSPATH(name, conn, inbuf, outbuf); - RESOLVE_DFSPATH(newname, conn, inbuf, outbuf); - - DEBUG(3,("reply_mv : %s -> %s\n",name,newname)); - - status = rename_internals(conn, name, newname, False); - if (!NT_STATUS_IS_OK(status)) { - return ERROR_NT(status); - } + RESOLVE_DFSPATH(name, conn, inbuf, outbuf); + RESOLVE_DFSPATH(newname, conn, inbuf, outbuf); + + DEBUG(3,("reply_mv : %s -> %s\n",name,newname)); + + outsize = rename_internals(conn, inbuf, outbuf, name, newname, False); + if(outsize == 0) { /* - * Win2k needs a changenotify request response before it will - * update after a rename.. - */ - process_pending_change_notify_queue((time_t)0); - outsize = set_message(outbuf,0,0,True); + * Win2k needs a changenotify request response before it will + * update after a rename.. + */ + + process_pending_change_notify_queue((time_t)0); + + outsize = set_message(outbuf,0,0,True); + } - END_PROFILE(SMBmv); - return(outsize); + END_PROFILE(SMBmv); + return(outsize); } /******************************************************************* @@ -3208,7 +3967,7 @@ static BOOL copy_file(char *src,char *dest1,connection_struct *conn, int ofun, pstrcpy(dest,dest1); if (target_is_directory) { - char *p = strrchr_m(src,'/'); + char *p = strrchr(src,'/'); if (p) p++; else @@ -3266,6 +4025,8 @@ static BOOL copy_file(char *src,char *dest1,connection_struct *conn, int ofun, return(ret == (SMB_OFF_T)src_sbuf.st_size); } + + /**************************************************************************** reply to a file copy. ****************************************************************************/ @@ -3293,9 +4054,8 @@ int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, *directory = *mask = 0; - p = smb_buf(inbuf); - p += srvstr_pull(inbuf, name, p, sizeof(name), -1, STR_TERMINATE); - p += srvstr_pull(inbuf, newname, p, sizeof(newname), -1, STR_TERMINATE); + pstrcpy(name,smb_buf(inbuf)); + pstrcpy(newname,smb_buf(inbuf) + 1 + strlen(name)); DEBUG(3,("reply_copy : %s -> %s\n",name,newname)); @@ -3303,7 +4063,7 @@ int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, /* can't currently handle inter share copies XXXX */ DEBUG(3,("Rejecting inter-share copy\n")); END_PROFILE(SMBcopy); - return ERROR_DOS(ERRSRV,ERRinvdevice); + return(ERROR(ERRSRV,ERRinvdevice)); } RESOLVE_DFSPATH(name, conn, inbuf, outbuf); @@ -3316,22 +4076,22 @@ int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, if ((flags&1) && target_is_directory) { END_PROFILE(SMBcopy); - return ERROR_DOS(ERRDOS,ERRbadfile); + return(ERROR(ERRDOS,ERRbadfile)); } if ((flags&2) && !target_is_directory) { END_PROFILE(SMBcopy); - return ERROR_DOS(ERRDOS,ERRbadpath); + return(ERROR(ERRDOS,ERRbadpath)); } if ((flags&(1<<5)) && VALID_STAT_OF_DIR(sbuf1)) { /* wants a tree copy! XXXX */ DEBUG(3,("Rejecting tree copy\n")); END_PROFILE(SMBcopy); - return ERROR_DOS(ERRSRV,ERRerror); + return(ERROR(ERRSRV,ERRerror)); } - p = strrchr_m(name,'/'); + p = strrchr(name,'/'); if (!p) { pstrcpy(directory,"./"); pstrcpy(mask,name); @@ -3410,7 +4170,7 @@ int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, if (exists) { END_PROFILE(SMBcopy); - return ERROR_DOS(ERRDOS,error); + return(ERROR(ERRDOS,error)); } else { if((errno == ENOENT) && (bad_path1 || bad_path2)) @@ -3444,10 +4204,11 @@ int reply_setdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size snum = SNUM(conn); if (!CAN_SETDIR(snum)) { END_PROFILE(pathworks_setdir); - return ERROR_DOS(ERRDOS,ERRnoaccess); + return(ERROR(ERRDOS,ERRnoaccess)); } - - srvstr_pull(inbuf, newdir, smb_buf(inbuf) + 1, sizeof(newdir), -1, STR_TERMINATE); + + pstrcpy(newdir,smb_buf(inbuf) + 1); + strlower(newdir); if (strlen(newdir) == 0) { ok = True; @@ -3460,7 +4221,7 @@ int reply_setdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size if (!ok) { END_PROFILE(pathworks_setdir); - return ERROR_DOS(ERRDOS,ERRbadpath); + return(ERROR(ERRDOS,ERRbadpath)); } outsize = set_message(outbuf,0,0,True); @@ -3526,6 +4287,7 @@ SMB_BIG_UINT get_lock_count( char *data, int data_offset, BOOL large_file_format /**************************************************************************** Pathetically try and map a 64 bit lock offset into 31 bits. I hate Windows :-). ****************************************************************************/ + static uint32 map_lock_offset(uint32 high, uint32 low) { unsigned int i; @@ -3610,184 +4372,187 @@ SMB_BIG_UINT get_lock_offset( char *data, int data_offset, BOOL large_file_forma int reply_lockingX(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize) { - files_struct *fsp = file_fsp(inbuf,smb_vwv2); - unsigned char locktype = CVAL(inbuf,smb_vwv3); - unsigned char oplocklevel = CVAL(inbuf,smb_vwv3+1); - uint16 num_ulocks = SVAL(inbuf,smb_vwv6); - uint16 num_locks = SVAL(inbuf,smb_vwv7); - SMB_BIG_UINT count = 0, offset = 0; - uint16 lock_pid; - int32 lock_timeout = IVAL(inbuf,smb_vwv4); - int i; - char *data; - BOOL large_file_format = (locktype & LOCKING_ANDX_LARGE_FILES)?True:False; - BOOL err; - NTSTATUS status; + files_struct *fsp = file_fsp(inbuf,smb_vwv2); + unsigned char locktype = CVAL(inbuf,smb_vwv3); + unsigned char oplocklevel = CVAL(inbuf,smb_vwv3+1); + uint16 num_ulocks = SVAL(inbuf,smb_vwv6); + uint16 num_locks = SVAL(inbuf,smb_vwv7); + SMB_BIG_UINT count = 0, offset = 0; + uint16 lock_pid; + int32 lock_timeout = IVAL(inbuf,smb_vwv4); + int i; + char *data; + uint32 ecode=0, dummy2; + int eclass=0, dummy1; + BOOL large_file_format = (locktype & LOCKING_ANDX_LARGE_FILES)?True:False; + BOOL err; + START_PROFILE(SMBlockingX); - START_PROFILE(SMBlockingX); - - CHECK_FSP(fsp,conn); - - data = smb_buf(inbuf); - - /* Check if this is an oplock break on a file - we have granted an oplock on. - */ - if ((locktype & LOCKING_ANDX_OPLOCK_RELEASE)) { - /* Client can insist on breaking to none. */ - BOOL break_to_none = (oplocklevel == 0); - - DEBUG(5,("reply_lockingX: oplock break reply (%u) from client for fnum = %d\n", - (unsigned int)oplocklevel, fsp->fnum )); + CHECK_FSP(fsp,conn); - /* - * Make sure we have granted an exclusive or batch oplock on this file. - */ - - if(!EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) { - DEBUG(0,("reply_lockingX: Error : oplock break from client for fnum = %d and \ + data = smb_buf(inbuf); + + /* Check if this is an oplock break on a file + we have granted an oplock on. + */ + if ((locktype & LOCKING_ANDX_OPLOCK_RELEASE)) + { + /* Client can insist on breaking to none. */ + BOOL break_to_none = (oplocklevel == 0); + + DEBUG(5,("reply_lockingX: oplock break reply (%u) from client for fnum = %d\n", + (unsigned int)oplocklevel, fsp->fnum )); + + /* + * Make sure we have granted an exclusive or batch oplock on this file. + */ + + if(!EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) + { + DEBUG(0,("reply_lockingX: Error : oplock break from client for fnum = %d and \ no oplock granted on this file (%s).\n", fsp->fnum, fsp->fsp_name)); - /* if this is a pure oplock break request then don't send a reply */ - if (num_locks == 0 && num_ulocks == 0) { - END_PROFILE(SMBlockingX); - return -1; - } else { - END_PROFILE(SMBlockingX); - return ERROR_DOS(ERRDOS,ERRlock); - } - } + /* if this is a pure oplock break request then don't send a reply */ + if (num_locks == 0 && num_ulocks == 0) { + END_PROFILE(SMBlockingX); + return -1; + } else { + END_PROFILE(SMBlockingX); + return ERROR(ERRDOS,ERRlock); + } + } - if (remove_oplock(fsp, break_to_none) == False) { - DEBUG(0,("reply_lockingX: error in removing oplock on file %s\n", - fsp->fsp_name )); - } - - /* if this is a pure oplock break request then don't send a reply */ - if (num_locks == 0 && num_ulocks == 0) { - /* Sanity check - ensure a pure oplock break is not a - chained request. */ - if(CVAL(inbuf,smb_vwv0) != 0xff) - DEBUG(0,("reply_lockingX: Error : pure oplock break is a chained %d request !\n", - (unsigned int)CVAL(inbuf,smb_vwv0) )); - END_PROFILE(SMBlockingX); - return -1; - } - } + if (remove_oplock(fsp, break_to_none) == False) { + DEBUG(0,("reply_lockingX: error in removing oplock on file %s\n", + fsp->fsp_name )); + } - /* - * We do this check *after* we have checked this is not a oplock break - * response message. JRA. - */ - - release_level_2_oplocks_on_change(fsp); - - /* Data now points at the beginning of the list - of smb_unlkrng structs */ - for(i = 0; i < (int)num_ulocks; i++) { - lock_pid = get_lock_pid( data, i, large_file_format); - count = get_lock_count( data, i, large_file_format); - offset = get_lock_offset( data, i, large_file_format, &err); - - /* - * There is no error code marked "stupid client bug".... :-). - */ - if(err) { - END_PROFILE(SMBlockingX); - return ERROR_DOS(ERRDOS,ERRnoaccess); - } + /* if this is a pure oplock break request then don't send a reply */ + if (num_locks == 0 && num_ulocks == 0) + { + /* Sanity check - ensure a pure oplock break is not a + chained request. */ + if(CVAL(inbuf,smb_vwv0) != 0xff) + DEBUG(0,("reply_lockingX: Error : pure oplock break is a chained %d request !\n", + (unsigned int)CVAL(inbuf,smb_vwv0) )); + END_PROFILE(SMBlockingX); + return -1; + } + } - DEBUG(10,("reply_lockingX: unlock start=%.0f, len=%.0f for pid %u, file %s\n", - (double)offset, (double)count, (unsigned int)lock_pid, fsp->fsp_name )); - - status = do_unlock(fsp,conn,lock_pid,count,offset); - if (NT_STATUS_V(status)) { - END_PROFILE(SMBlockingX); - return ERROR_NT(status); - } - } + /* + * We do this check *after* we have checked this is not a oplock break + * response message. JRA. + */ - /* Setup the timeout in seconds. */ - lock_timeout = ((lock_timeout == -1) ? -1 : lock_timeout/1000); - - /* Now do any requested locks */ - data += ((large_file_format ? 20 : 10)*num_ulocks); - - /* Data now points at the beginning of the list - of smb_lkrng structs */ - - for(i = 0; i < (int)num_locks; i++) { - lock_pid = get_lock_pid( data, i, large_file_format); - count = get_lock_count( data, i, large_file_format); - offset = get_lock_offset( data, i, large_file_format, &err); - - /* - * There is no error code marked "stupid client bug".... :-). - */ - if(err) { - END_PROFILE(SMBlockingX); - return ERROR_DOS(ERRDOS,ERRnoaccess); - } - - DEBUG(10,("reply_lockingX: lock start=%.0f, len=%.0f for pid %u, file %s\n", - (double)offset, (double)count, (unsigned int)lock_pid, fsp->fsp_name )); - - status = do_lock(fsp,conn,lock_pid, count,offset, - ((locktype & 1) ? READ_LOCK : WRITE_LOCK)); - if (NT_STATUS_V(status)) { - if ((lock_timeout != 0) && lp_blocking_locks(SNUM(conn))) { - /* - * A blocking lock was requested. Package up - * this smb into a queued request and push it - * onto the blocking lock queue. - */ - if(push_blocking_lock_request(inbuf, length, lock_timeout, i)) { - END_PROFILE(SMBlockingX); - return -1; - } - } - break; - } - } - - /* If any of the above locks failed, then we must unlock - all of the previous locks (X/Open spec). */ - if (i != num_locks && num_locks != 0) { - /* - * Ensure we don't do a remove on the lock that just failed, - * as under POSIX rules, if we have a lock already there, we - * will delete it (and we shouldn't) ..... - */ - for(i--; i >= 0; i--) { - lock_pid = get_lock_pid( data, i, large_file_format); - count = get_lock_count( data, i, large_file_format); - offset = get_lock_offset( data, i, large_file_format, &err); - - /* - * There is no error code marked "stupid client bug".... :-). - */ - if(err) { - END_PROFILE(SMBlockingX); - return ERROR_DOS(ERRDOS,ERRnoaccess); - } - - do_unlock(fsp,conn,lock_pid,count,offset); - } - END_PROFILE(SMBlockingX); - return ERROR_NT(status); + release_level_2_oplocks_on_change(fsp); + + /* Data now points at the beginning of the list + of smb_unlkrng structs */ + for(i = 0; i < (int)num_ulocks; i++) { + lock_pid = get_lock_pid( data, i, large_file_format); + count = get_lock_count( data, i, large_file_format); + offset = get_lock_offset( data, i, large_file_format, &err); + + /* + * There is no error code marked "stupid client bug".... :-). + */ + if(err) { + END_PROFILE(SMBlockingX); + return ERROR(ERRDOS,ERRnoaccess); + } + + DEBUG(10,("reply_lockingX: unlock start=%.0f, len=%.0f for pid %u, file %s\n", + (double)offset, (double)count, (unsigned int)lock_pid, fsp->fsp_name )); + + if(!do_unlock(fsp,conn,lock_pid,count,offset, &eclass, &ecode)) { + END_PROFILE(SMBlockingX); + return ERROR(eclass,ecode); + } + } + + /* Setup the timeout in seconds. */ + lock_timeout = ((lock_timeout == -1) ? -1 : lock_timeout/1000); + + /* Now do any requested locks */ + data += ((large_file_format ? 20 : 10)*num_ulocks); + + /* Data now points at the beginning of the list + of smb_lkrng structs */ + + for(i = 0; i < (int)num_locks; i++) { + lock_pid = get_lock_pid( data, i, large_file_format); + count = get_lock_count( data, i, large_file_format); + offset = get_lock_offset( data, i, large_file_format, &err); + + /* + * There is no error code marked "stupid client bug".... :-). + */ + if(err) { + END_PROFILE(SMBlockingX); + return ERROR(ERRDOS,ERRnoaccess); + } + + DEBUG(10,("reply_lockingX: lock start=%.0f, len=%.0f for pid %u, file %s\n", + (double)offset, (double)count, (unsigned int)lock_pid, fsp->fsp_name )); + + if(!do_lock(fsp,conn,lock_pid, count,offset, ((locktype & 1) ? READ_LOCK : WRITE_LOCK), + &eclass, &ecode)) { + if((ecode == ERRlock) && (lock_timeout != 0) && lp_blocking_locks(SNUM(conn))) { + /* + * A blocking lock was requested. Package up + * this smb into a queued request and push it + * onto the blocking lock queue. + */ + if(push_blocking_lock_request(inbuf, length, lock_timeout, i)) { + END_PROFILE(SMBlockingX); + return -1; } + } + break; + } + } - set_message(outbuf,2,0,True); - - DEBUG( 3, ( "lockingX fnum=%d type=%d num_locks=%d num_ulocks=%d\n", - fsp->fnum, (unsigned int)locktype, num_locks, num_ulocks ) ); - + /* If any of the above locks failed, then we must unlock + all of the previous locks (X/Open spec). */ + if(i != num_locks && num_locks != 0) { + /* + * Ensure we don't do a remove on the lock that just failed, + * as under POSIX rules, if we have a lock already there, we + * will delete it (and we shouldn't) ..... + */ + for(i--; i >= 0; i--) { + lock_pid = get_lock_pid( data, i, large_file_format); + count = get_lock_count( data, i, large_file_format); + offset = get_lock_offset( data, i, large_file_format, &err); + + /* + * There is no error code marked "stupid client bug".... :-). + */ + if(err) { END_PROFILE(SMBlockingX); - return chain_reply(inbuf,outbuf,length,bufsize); + return ERROR(ERRDOS,ERRnoaccess); + } + + do_unlock(fsp,conn,lock_pid,count,offset,&dummy1,&dummy2); + } + END_PROFILE(SMBlockingX); + return ERROR(eclass,ecode); + } + + set_message(outbuf,2,0,True); + + DEBUG( 3, ( "lockingX fnum=%d type=%d num_locks=%d num_ulocks=%d\n", + fsp->fnum, (unsigned int)locktype, num_locks, num_ulocks ) ); + + END_PROFILE(SMBlockingX); + return chain_reply(inbuf,outbuf,length,bufsize); } +/* Back from the dead for OS/2..... JRA. */ + /**************************************************************************** - Reply to a SMBreadbmpx (read block multiplex) request. + Reply to a SMBreadbmpx (read block multiplex) request ****************************************************************************/ int reply_readbmpx(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize) @@ -3807,13 +4572,14 @@ int reply_readbmpx(connection_struct *conn, char *inbuf,char *outbuf,int length, /* this function doesn't seem to work - disable by default */ if (!lp_readbmpx()) { END_PROFILE(SMBreadBmpx); - return ERROR_DOS(ERRSRV,ERRuseSTD); + return(ERROR(ERRSRV,ERRuseSTD)); } outsize = set_message(outbuf,8,0,True); CHECK_FSP(fsp,conn); CHECK_READ(fsp); + CHECK_ERROR(fsp); startpos = IVAL(inbuf,smb_vwv1); maxcount = SVAL(inbuf,smb_vwv3); @@ -3828,14 +4594,14 @@ int reply_readbmpx(connection_struct *conn, char *inbuf,char *outbuf,int length, tcount = maxcount; total_read = 0; - if (is_locked(fsp,conn,(SMB_BIG_UINT)maxcount,(SMB_BIG_UINT)startpos, READ_LOCK,False)) { + if (is_locked(fsp,conn,(SMB_BIG_UINT)maxcount,(SMB_BIG_UINT)startpos, READ_LOCK, False)) { END_PROFILE(SMBreadBmpx); - return ERROR_DOS(ERRDOS,ERRlock); + return(ERROR(ERRDOS,ERRlock)); } do { size_t N = MIN(max_per_packet,tcount-total_read); - + nread = read_file(fsp,data,startpos,N); if (nread <= 0) @@ -3862,65 +4628,6 @@ int reply_readbmpx(connection_struct *conn, char *inbuf,char *outbuf,int length, } /**************************************************************************** - Reply to a SMBsetattrE. -****************************************************************************/ - -int reply_setattrE(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize) -{ - struct utimbuf unix_times; - int outsize = 0; - files_struct *fsp = file_fsp(inbuf,smb_vwv0); - START_PROFILE(SMBsetattrE); - - outsize = set_message(outbuf,0,0,True); - - CHECK_FSP(fsp,conn); - - /* Convert the DOS times into unix times. Ignore create - time as UNIX can't set this. - */ - unix_times.actime = make_unix_date2(inbuf+smb_vwv3); - unix_times.modtime = make_unix_date2(inbuf+smb_vwv5); - - /* - * Patch from Ray Frush <frush@engr.colostate.edu> - * Sometimes times are sent as zero - ignore them. - */ - - if ((unix_times.actime == 0) && (unix_times.modtime == 0)) - { - /* Ignore request */ - if( DEBUGLVL( 3 ) ) - { - dbgtext( "reply_setattrE fnum=%d ", fsp->fnum); - dbgtext( "ignoring zero request - not setting timestamps of 0\n" ); - } - END_PROFILE(SMBsetattrE); - return(outsize); - } - else if ((unix_times.actime != 0) && (unix_times.modtime == 0)) - { - /* set modify time = to access time if modify time was 0 */ - unix_times.modtime = unix_times.actime; - } - - /* Set the date on this file */ - if(file_utime(conn, fsp->fsp_name, &unix_times)) { - END_PROFILE(SMBsetattrE); - return ERROR_DOS(ERRDOS,ERRnoaccess); - } - - DEBUG( 3, ( "reply_setattrE fnum=%d actime=%d modtime=%d\n", - fsp->fnum, (int)unix_times.actime, (int)unix_times.modtime ) ); - - END_PROFILE(SMBsetattrE); - return(outsize); -} - - -/* Back from the dead for OS/2..... JRA. */ - -/**************************************************************************** Reply to a SMBwritebmpx (write block multiplex primary) request. ****************************************************************************/ @@ -3955,7 +4662,7 @@ int reply_writebmpx(connection_struct *conn, char *inbuf,char *outbuf, int size, if (is_locked(fsp,conn,(SMB_BIG_UINT)tcount,(SMB_BIG_UINT)startpos,WRITE_LOCK,False)) { END_PROFILE(SMBwriteBmpx); - return(ERROR_DOS(ERRDOS,ERRlock)); + return(ERROR(ERRDOS,ERRlock)); } nwritten = write_file(fsp,data,startpos,numtowrite); @@ -3979,10 +4686,11 @@ int reply_writebmpx(connection_struct *conn, char *inbuf,char *outbuf, int size, wbms = fsp->wbmpx_ptr; /* Use an existing struct */ else wbms = (write_bmpx_struct *)malloc(sizeof(write_bmpx_struct)); + if(!wbms) { DEBUG(0,("Out of memory in reply_readmpx\n")); END_PROFILE(SMBwriteBmpx); - return(ERROR_DOS(ERRSRV,ERRnoresource)); + return(ERROR(ERRSRV,ERRnoresource)); } wbms->wr_mode = write_through; wbms->wr_discard = False; /* No errors yet */ @@ -3992,24 +4700,23 @@ int reply_writebmpx(connection_struct *conn, char *inbuf,char *outbuf, int size, fsp->wbmpx_ptr = wbms; } - /* We are returning successfully, set the message type back to - SMBwritebmpx */ + /* We are returning successfully, set the message type back to SMBwritebmpx */ CVAL(outbuf,smb_com) = SMBwriteBmpx; outsize = set_message(outbuf,1,0,True); - + SSVALS(outbuf,smb_vwv0,-1); /* We don't support smb_remaining */ DEBUG( 3, ( "writebmpx fnum=%d num=%d wrote=%d\n", - fsp->fnum, (int)numtowrite, (int)nwritten ) ); + fsp->fnum, (int)numtowrite, (int)nwritten ) ); if (write_through && tcount==nwritten) { - /* We need to send both a primary and a secondary response */ + /* We need to send both a primary and a secondary response. */ smb_setlen(outbuf,outsize - 4); if (!send_smb(smbd_server_fd(),outbuf)) - exit_server("reply_writebmpx: send_smb failed.\n"); + exit_server("reply_writeBmpx : send_smb failed.\n"); - /* Now the secondary */ + /* Now the secondary. */ outsize = set_message(outbuf,1,0,True); CVAL(outbuf,smb_com) = SMBwritec; SSVAL(outbuf,smb_vwv0,nwritten); @@ -4051,8 +4758,7 @@ int reply_writebs(connection_struct *conn, char *inbuf,char *outbuf, int dum_siz /* We need to send an SMBwriteC response, not an SMBwritebs */ CVAL(outbuf,smb_com) = SMBwritec; - /* This fd should have an auxiliary struct attached, - check that it does */ + /* This fd should have an auxiliary struct attached, check that it does */ wbms = fsp->wbmpx_ptr; if(!wbms) { END_PROFILE(SMBwriteBs); @@ -4080,7 +4786,7 @@ int reply_writebs(connection_struct *conn, char *inbuf,char *outbuf, int dum_siz free((char *)wbms); fsp->wbmpx_ptr = NULL; END_PROFILE(SMBwriteBs); - return(ERROR_DOS(ERRHRD,ERRdiskfull)); + return(ERROR(ERRHRD,ERRdiskfull)); } END_PROFILE(SMBwriteBs); return(CACHE_ERROR(wbms,ERRHRD,ERRdiskfull)); @@ -4110,7 +4816,64 @@ int reply_writebs(connection_struct *conn, char *inbuf,char *outbuf, int dum_siz } /**************************************************************************** - Reply to a SMBgetattrE. + Reply to a SMBsetattrE. +****************************************************************************/ + +int reply_setattrE(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize) +{ + struct utimbuf unix_times; + int outsize = 0; + files_struct *fsp = file_fsp(inbuf,smb_vwv0); + START_PROFILE(SMBsetattrE); + + outsize = set_message(outbuf,0,0,True); + + CHECK_FSP(fsp,conn); + + /* Convert the DOS times into unix times. Ignore create + time as UNIX can't set this. + */ + unix_times.actime = make_unix_date2(inbuf+smb_vwv3); + unix_times.modtime = make_unix_date2(inbuf+smb_vwv5); + + /* + * Patch from Ray Frush <frush@engr.colostate.edu> + * Sometimes times are sent as zero - ignore them. + */ + + if ((unix_times.actime == 0) && (unix_times.modtime == 0)) + { + /* Ignore request */ + if( DEBUGLVL( 3 ) ) + { + dbgtext( "reply_setattrE fnum=%d ", fsp->fnum); + dbgtext( "ignoring zero request - not setting timestamps of 0\n" ); + } + END_PROFILE(SMBsetattrE); + return(outsize); + } + else if ((unix_times.actime != 0) && (unix_times.modtime == 0)) + { + /* set modify time = to access time if modify time was 0 */ + unix_times.modtime = unix_times.actime; + } + + /* Set the date on this file */ + if(file_utime(conn, fsp->fsp_name, &unix_times)) { + END_PROFILE(SMBsetattrE); + return(ERROR(ERRDOS,ERRnoaccess)); + } + + DEBUG( 3, ( "reply_setattrE fnum=%d actime=%d modtime=%d\n", + fsp->fnum, (int)unix_times.actime, (int)unix_times.modtime ) ); + + END_PROFILE(SMBsetattrE); + return(outsize); +} + + +/**************************************************************************** + reply to a SMBgetattrE ****************************************************************************/ int reply_getattrE(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize) |