diff options
Diffstat (limited to 'source/smbd/reply.c')
-rw-r--r-- | source/smbd/reply.c | 2208 |
1 files changed, 1408 insertions, 800 deletions
diff --git a/source/smbd/reply.c b/source/smbd/reply.c index a881e135c08..50b31d7d681 100644 --- a/source/smbd/reply.c +++ b/source/smbd/reply.c @@ -1,9 +1,9 @@ /* - Unix SMB/CIFS implementation. + Unix SMB/Netbios implementation. + 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 @@ -23,6 +23,7 @@ makes to handle specific protocols */ + #include "includes.h" /* look in server.c for some explanation of these variables */ @@ -33,14 +34,30 @@ extern char magic_char; extern BOOL case_sensitive; 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 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() ); + } +} + /**************************************************************************** - Reply to an special message. + reply to an special message ****************************************************************************/ int reply_special(char *inbuf,char *outbuf) @@ -49,12 +66,11 @@ 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; - static BOOL already_got_session = False; - *name1 = *name2 = 0; memset(outbuf,'\0',smb_size); @@ -63,11 +79,6 @@ int reply_special(char *inbuf,char *outbuf) switch (msg_type) { case 0x81: /* session request */ - - if (already_got_session) { - exit_server("multiple session request not permitted"); - } - SCVAL(outbuf,0,0x82); SCVAL(outbuf,3,0); if (name_len(inbuf+4) > 50 || @@ -80,45 +91,49 @@ int reply_special(char *inbuf,char *outbuf) DEBUG(2,("netbios connect: name1=%s name2=%s\n", name1,name2)); - name1[15] = 0; + fstrcpy(remote_machine,name2); + remote_machine[15] = 0; + trim_string(remote_machine," "," "); + strlower(remote_machine); + alpha_strcpy(remote_machine,remote_machine,SAFE_NETBIOS_CHARS,sizeof(remote_machine)-1); - len = strlen(name2); + fstrcpy(local_machine,name1); + len = strlen(local_machine); if (len == 16) { - name_type = name2[15]; - name2[15] = 0; + name_type = local_machine[15]; + local_machine[15] = 0; } - - set_local_machine_name(name1); - set_remote_machine_name(name2); + trim_string(local_machine," "," "); + strlower(local_machine); + alpha_strcpy(local_machine,local_machine,SAFE_NETBIOS_CHARS,sizeof(local_machine)-1); DEBUG(2,("netbios connect: local=%s remote=%s\n", - get_local_machine_name(), get_remote_machine_name() )); + local_machine, remote_machine )); if (name_type == 'R') { /* We are being asked for a pathworks session --- no thanks! */ - SCVAL(outbuf, 0,0x83); + SCVAL(outbuf, 0, 0x83); 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(get_remote_machine_name()); + add_session_user(remote_machine); } reload_services(True); reopen_logs(); - claim_connection(NULL,"",0,True,FLAG_MSG_GENERAL|FLAG_MSG_SMBD); + if (lp_status(-1)) + claim_connection(NULL,"",0,True); - already_got_session = True; break; case 0x89: /* session keepalive request (some old clients produce this?) */ - SCVAL(outbuf,0,SMBkeepalive); + SCVAL(outbuf,0,0x85); SCVAL(outbuf,3,0); break; @@ -128,7 +143,7 @@ int reply_special(char *inbuf,char *outbuf) DEBUG(0,("Unexpected session response\n")); break; - case SMBkeepalive: /* session keepalive */ + case 0x85: /* session keepalive */ default: return(0); } @@ -139,6 +154,54 @@ int reply_special(char *inbuf,char *outbuf) return(outsize); } + +/******************************************************************* +work out what error to give to a failed connection +********************************************************************/ + +static int connection_error(char *outbuf, int ecode) +{ + if (ecode == ERRnoipc || ecode == ERRnosuchshare) + return(ERROR_DOS(ERRDOS,ecode)); + + return(ERROR_DOS(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. ****************************************************************************/ @@ -146,43 +209,54 @@ int reply_special(char *inbuf,char *outbuf) int reply_tcon(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize) { - const char *service; - pstring service_buf; + 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; - DATA_BLOB password_blob; - + int ecode = -1; START_PROFILE(SMBtcon); - *service_buf = *password = *dev = 0; + *service = *user = *password = *dev = 0; - p = smb_buf(inbuf)+1; - p += srvstr_pull_buf(inbuf, service_buf, p, sizeof(service), STR_TERMINATE) + 1; - pwlen = srvstr_pull_buf(inbuf, password, p, sizeof(password), STR_TERMINATE) + 1; - p += pwlen; - p += srvstr_pull_buf(inbuf, dev, p, sizeof(dev), STR_TERMINATE) + 1; + parse_connect(smb_buf(inbuf)+1,service,user,password,&pwlen,dev); - p = strrchr_m(service_buf,'\\'); - if (p) { - service = p+1; - } else { - service = service_buf; + /* + * 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)); } - password_blob = data_blob(password, pwlen+1); + /* + * Ensure the user and password names are in UNIX codepage format. + */ + + pstrcpy(user,dos_to_unix_static(user)); + if (!doencrypt) + pstrcpy(password,dos_to_unix_static(password)); - conn = make_connection(service,password_blob,dev,vuid,&nt_status); + /* + * Pass the user through the NT -> unix user mapping + * function. + */ + + (void)map_username(user); - data_blob_clear_free(&password_blob); + /* + * 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(outbuf,ecode)); } outsize = set_message(outbuf,2,0,True); @@ -190,8 +264,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); @@ -204,17 +278,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; - DATA_BLOB password; + 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; - extern BOOL global_encrypted_passwords_negotiated; - START_PROFILE(SMBtconX); - - *service = *devicename = 0; + char *path; + char *p; + START_PROFILE(SMBtconX); + + *service = *user = *password = *devicename = 0; /* we might have to close an old one */ if ((SVAL(inbuf,smb_vwv2) & 0x1) && conn) { @@ -222,67 +297,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_DOS(ERRDOS,ERRbuftoosmall)); } - if (global_encrypted_passwords_negotiated) { - password = data_blob(smb_buf(inbuf),passlen); - } else { - password = data_blob(smb_buf(inbuf),passlen+1); - /* Ensure correct termination */ - password.data[passlen]=0; + memcpy(password,smb_buf(inbuf),passlen); + password[passlen]=0; + path = smb_buf(inbuf) + passlen; + + if (passlen != 24) { + if (strequal(password," ")) + *password = 0; + passlen = strlen(password); } - p = smb_buf(inbuf) + passlen; - p += srvstr_pull_buf(inbuf, path, p, sizeof(path), STR_TERMINATE); - /* * 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)); } - 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,devicename,vuid,&nt_status); - - data_blob_clear_free(&password); + /* + * 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_static(user)); + if (!doencrypt) + pstrcpy(password,dos_to_unix_static(password)); + + /* + * 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(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 */ @@ -293,8 +392,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); @@ -304,10 +403,10 @@ int reply_tcon_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt return chain_reply(inbuf,outbuf,length,bufsize); } + /**************************************************************************** - Reply to an unknown type. + reply to an unknown type ****************************************************************************/ - int reply_unknown(char *inbuf,char *outbuf) { int type; @@ -320,9 +419,8 @@ int reply_unknown(char *inbuf,char *outbuf) } /**************************************************************************** - Reply to an ioctl. + reply to an ioctl ****************************************************************************/ - int reply_ioctl(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize) { @@ -336,7 +434,8 @@ int reply_ioctl(connection_struct *conn, DEBUG(4, ("Received IOCTL (code 0x%x)\n", ioctl_code)); - switch (ioctl_code) { + switch (ioctl_code) + { case IOCTL_QUERY_JOB_INFO: replysize = 32; break; @@ -351,15 +450,13 @@ int reply_ioctl(connection_struct *conn, SSVAL(outbuf,smb_vwv6,52); /* Offset to data */ p = smb_buf(outbuf) + 1; /* Allow for alignment */ - switch (ioctl_code) { - case IOCTL_QUERY_JOB_INFO: - { - uint16 rap_jobid = pjobid_to_rap(SNUM(fsp->conn), fsp->print_jobid); - SSVAL(p,0,rap_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); - break; - } + switch (ioctl_code) + { + case IOCTL_QUERY_JOB_INFO: + SSVAL(p,0,fsp->print_jobid); /* Job number */ + StrnCpy(p+2, global_myname, 15); /* Our NetBIOS name */ + StrnCpy(p+18, lp_servicename(SNUM(conn)), 13); /* Service name */ + break; } END_PROFILE(SMBioctl); @@ -367,56 +464,707 @@ int reply_ioctl(connection_struct *conn, } /**************************************************************************** - Reply to a chkpth. + Always return an error: it's just a matter of which one... + ****************************************************************************/ + +static int session_trust_account(connection_struct *conn, char *inbuf, char *outbuf, char *user, + char *smb_passwd, int smb_passlen, + char *smb_nt_passwd, int smb_nt_passlen) +{ + 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)); + pdb_free_sam(sam_trust_acct); + 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)); + pdb_free_sam(sam_trust_acct); + 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)); + pdb_free_sam(sam_trust_acct); + 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)); + pdb_free_sam(sam_trust_acct); + 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)); + pdb_free_sam(sam_trust_acct); + return(ERROR_BOTH(NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT,ERRDOS,1808)); + } + } + + /* don't know what to do: indicate logon failure */ + pdb_free_sam(sam_trust_acct); + return(ERROR_BOTH(NT_STATUS_LOGON_FAILURE,ERRDOS,1326)); +} + +/**************************************************************************** + Create a UNIX user on demand. ****************************************************************************/ -int reply_chkpth(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize) +int smb_create_user(char *unix_user, char *homedir) { - int outsize = 0; - int mode; - pstring name; - BOOL ok = False; - BOOL bad_path = False; - SMB_STRUCT_STAT sbuf; - START_PROFILE(SMBchkpth); + pstring add_script; + int ret; - srvstr_pull_buf(inbuf, name, smb_buf(inbuf) + 1, sizeof(name), STR_TERMINATE); + 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; +} - RESOLVE_DFSPATH(name, conn, inbuf, outbuf); +/**************************************************************************** + Delete a UNIX user on demand. +****************************************************************************/ - unix_convert(name,conn,0,&bad_path,&sbuf); +static int smb_delete_user(char *unix_user) +{ + pstring del_script; + int ret; - mode = SVAL(inbuf,smb_vwv0); + /* + * Sanity check -- do not delete 'root' account + */ - if (check_name(name,conn)) { - if (VALID_STAT(sbuf) || vfs_stat(conn,name,&sbuf) == 0) - ok = S_ISDIR(sbuf.st_mode); + if (StrCaseCmp("root", unix_user) == 0) { + DEBUG(0,("smb_delete_user: Will not delete the [%s] user account!\n", unix_user)); + return -1; } - 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); + 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 +****************************************************************************/ - return(UNIXERROR(ERRDOS,ERRbadpath)); +static BOOL check_domain_match(char *user, char *domain) +{ + /* + * If we aren't serving to trusted domains, we must make sure that + * the validation request comes from an account in the same domain + * as the Samba server + */ + + if (!lp_allow_trusted_domains() && + !strequal(lp_workgroup(), domain) ) { + DEBUG(1, ("check_domain_match: Attempt to connect as user %s from domain %s denied.\n", user, domain)); + return False; + } else { + return True; + } +} + +/**************************************************************************** + Check for a valid username and password in security=server mode. +****************************************************************************/ + +static BOOL check_server_security(char *orig_user, char *domain, char *unix_user, + char *smb_apasswd, int smb_apasslen, + char *smb_ntpasswd, int smb_ntpasslen) +{ + BOOL ret = False; + + if(lp_security() != SEC_SERVER) + return False; + + if (!check_domain_match(orig_user, domain)) + return False; + + ret = server_validate(orig_user, domain, + smb_apasswd, smb_apasslen, + smb_ntpasswd, smb_ntpasslen); + + if(ret) { + /* + * User validated ok against Domain controller. + * If the admin wants us to try and create a UNIX + * user on the fly, do so. + * Note that we can never delete users when in server + * level security as we never know if it was a failure + * due to a bad password, or the user really doesn't exist. + */ + + if(lp_adduser_script() && !smb_getpwnam(unix_user,True)) + smb_create_user(unix_user, NULL); } - outsize = set_message(outbuf,0,0,True); + return ret; +} - DEBUG(3,("chkpth %s mode=%d\n", name, mode)); +/**************************************************************************** + Check for a valid username and password in security=domain mode. +****************************************************************************/ - END_PROFILE(SMBchkpth); - return(outsize); +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, NT_USER_TOKEN **pptoken) +{ + 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, pptoken); + + 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; + NT_USER_TOKEN *ptok = NULL; + + 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_DOS(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_static(user)); + + 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_DOS(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_static(smb_apasswd)); + pstrcpy(smb_ntpasswd,dos_to_unix_static(smb_ntpasswd)); + } + + } 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_static(smb_apasswd)); + + /* 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_static(user)); + fstrcpy(domain, dos_to_unix_static(p)); + 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_DOS(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", + domain, 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, &ptok) && + !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) + { + delete_nt_token(&ptok); + 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) + { + SAM_ACCOUNT *sampass = NULL; + + pdb_init_sam(&sampass); + + /* + * This is really bad form. We know that password_ok() failed, + * but the return value can't distinguish between a non-existent user + * and a bad password. So we try to look the user up again here + * to see if he or she exists. We must look up the user in the + * "smb passwd file" and not /etc/passwd so that we don't + * get confused when the two don't have a one-to-one correspondence. + * e.g. a standard UNIX account such as "operator" --jerry + */ + + if (pdb_getsampwnam(sampass, user)) + { + delete_nt_token(&ptok); + DEBUG(1,("Rejecting user '%s': bad password\n", user)); + END_PROFILE(SMBsesssetupX); + pdb_free_sam(sampass); + return ERROR_BOTH(NT_STATUS_LOGON_FAILURE,ERRSRV,ERRbadpw); + } + + pdb_free_sam(sampass); + } + + /* + * ..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_service_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); 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) { + delete_nt_token(&ptok); + 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,&ptok); + + delete_nt_token(&ptok); + + if (sess_vuid == -1) { + END_PROFILE(SMBsesssetupX); + return(ERROR_DOS(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 getatr. + reply to a chkpth ****************************************************************************/ +int reply_chkpth(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize) +{ + int outsize = 0; + int mode; + pstring name; + BOOL ok = False; + BOOL bad_path = False; + SMB_STRUCT_STAT sbuf; + START_PROFILE(SMBchkpth); + + pstrcpy(name,smb_buf(inbuf) + 1); + + RESOLVE_DFSPATH(name, conn, inbuf, outbuf); + + unix_convert(name,conn,0,&bad_path,&sbuf); + + mode = SVAL(inbuf,smb_vwv0); + if (check_name(name,conn)) { + if (VALID_STAT(sbuf) || vfs_stat(conn,name,&sbuf) == 0) + ok = S_ISDIR(sbuf.st_mode); + } + + 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); + } + + return(UNIXERROR(ERRDOS,ERRbadpath)); + } + + outsize = set_message(outbuf,0,0,True); + + DEBUG(3,("chkpth %s mode=%d\n", name, mode)); + + END_PROFILE(SMBchkpth); + return(outsize); +} + + +/**************************************************************************** + reply to a getatr +****************************************************************************/ int reply_getatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize) { pstring fname; @@ -427,11 +1175,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_buf(inbuf, fname, p, sizeof(fname), STR_TERMINATE); + + pstrcpy(fname,smb_buf(inbuf) + 1); RESOLVE_DFSPATH(fname, conn, inbuf, outbuf); @@ -489,10 +1235,10 @@ int reply_getatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size return(outsize); } + /**************************************************************************** - Reply to a setatr. + reply to a setatr ****************************************************************************/ - int reply_setatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize) { pstring fname; @@ -502,12 +1248,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_buf(inbuf, fname, p, sizeof(fname), STR_TERMINATE); + + pstrcpy(fname,smb_buf(inbuf) + 1); unix_convert(fname,conn,0,&bad_path,&sbuf); mode = SVAL(inbuf,smb_vwv0); @@ -538,10 +1281,10 @@ int reply_setatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size return(outsize); } + /**************************************************************************** - Reply to a dskattr. + reply to a dskattr ****************************************************************************/ - int reply_dskattr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize) { int outsize = 0; @@ -586,11 +1329,11 @@ int reply_dskattr(connection_struct *conn, char *inbuf,char *outbuf, int dum_siz return(outsize); } + /**************************************************************************** - Reply to a search. - Can be called from SMBsearch, SMBffirst or SMBfunique. + reply to a search + Can be called from SMBsearch, SMBffirst or SMBfunique. ****************************************************************************/ - int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize) { pstring mask; @@ -608,7 +1351,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; @@ -626,28 +1369,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_buf(inbuf, path, p, sizeof(path), 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); @@ -659,7 +1400,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 @@ -668,16 +1409,12 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size if (strlen(directory) == 0) pstrcpy(directory,"./"); memset((char *)status,'\0',21); - SCVAL(status,0,(dirtype & 0x1F)); + SCVAL(status,0,dirtype); } else { - int status_dirtype; - memcpy(status,p,21); - status_dirtype = CVAL(status,0) & 0x1F; - if (status_dirtype != (dirtype & 0x1F)) - dirtype = status_dirtype; - + memcpy(status,smb_buf(inbuf) + 1 + strlen(path) + 4,21); + dirtype = CVAL(status,0) & 0x1F; conn->dirptr = dptr_fetch(status+12,&dptr_num); if (!conn->dirptr) goto SearchEmpty; @@ -750,11 +1487,11 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size SearchEmpty: - if (numentries == 0 || !ok) + if ( (numentries == 0) || !ok) { - SCVAL(outbuf,smb_rcls,ERRDOS); - SSVAL(outbuf,smb_err,ERRnofiles); - dptr_close(&dptr_num); + SCVAL(outbuf,smb_rcls,ERRDOS); + SSVAL(outbuf,smb_err,ERRnofiles); + dptr_close(&dptr_num); } /* If we were called as SMBffirst with smb_search_id == NULL @@ -780,7 +1517,7 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size if (Protocol >= PROTOCOL_NT1) SSVAL(outbuf,smb_flg2,SVAL(outbuf, smb_flg2) | FLAGS2_IS_LONG_NAME); - + outsize += DIR_STRUCT_SIZE*numentries; smb_setlen(outbuf,outsize - 4); @@ -795,34 +1532,30 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size return(outsize); } + /**************************************************************************** - Reply to a fclose (stop directory search). + reply to a fclose (stop directory search) ****************************************************************************/ - int reply_fclose(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize) { 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_buf(inbuf, path, p, sizeof(path), 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); } - 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,8 +1570,9 @@ int reply_fclose(connection_struct *conn, char *inbuf,char *outbuf, int dum_size return(outsize); } + /**************************************************************************** - Reply to an open. + reply to an open ****************************************************************************/ int reply_open(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize) @@ -859,7 +1593,7 @@ int reply_open(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, share_mode = SVAL(inbuf,smb_vwv0); - srvstr_pull_buf(inbuf, fname, smb_buf(inbuf)+1, sizeof(fname), STR_TERMINATE); + pstrcpy(fname,smb_buf(inbuf)+1); RESOLVE_DFSPATH(fname, conn, inbuf, outbuf); @@ -899,19 +1633,19 @@ int reply_open(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, SSVAL(outbuf,smb_vwv6,rmode); if (oplock_request && lp_fake_oplocks(SNUM(conn))) { - SCVAL(outbuf,smb_flg,CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED); + SCVAL(outbuf,smb_flg, CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED); } if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) - SCVAL(outbuf,smb_flg,CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED); + SCVAL(outbuf,smb_flg, CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED); END_PROFILE(SMBopen); return(outsize); } + /**************************************************************************** - Reply to an open and X. + reply to an open and X ****************************************************************************/ - int reply_open_and_X(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize) { pstring fname; @@ -949,7 +1683,8 @@ int reply_open_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt } /* XXXX we need to handle passed times, sattr and flags */ - srvstr_pull_buf(inbuf, fname, smb_buf(inbuf), sizeof(fname), STR_TERMINATE); + + pstrcpy(fname,smb_buf(inbuf)); RESOLVE_DFSPATH(fname, conn, inbuf, outbuf); @@ -995,7 +1730,7 @@ int reply_open_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt */ if (core_oplock_request && lp_fake_oplocks(SNUM(conn))) { - SCVAL(outbuf,smb_flg,CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED); + SCVAL(outbuf,smb_flg, CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED); } if(core_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) { @@ -1017,10 +1752,10 @@ int reply_open_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt return chain_reply(inbuf,outbuf,length,bufsize); } + /**************************************************************************** - Reply to a SMBulogoffX. + reply to a SMBulogoffX ****************************************************************************/ - int reply_ulogoffX(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize) { uint16 vuid = SVAL(inbuf,smb_uid); @@ -1047,10 +1782,10 @@ int reply_ulogoffX(connection_struct *conn, char *inbuf,char *outbuf,int length, return chain_reply(inbuf,outbuf,length,bufsize); } + /**************************************************************************** - Reply to a mknew or a create. + reply to a mknew or a create ****************************************************************************/ - int reply_mknew(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize) { pstring fname; @@ -1068,7 +1803,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_buf(inbuf, fname, smb_buf(inbuf) + 1, sizeof(fname), STR_TERMINATE); + pstrcpy(fname,smb_buf(inbuf)+1); RESOLVE_DFSPATH(fname, conn, inbuf, outbuf); @@ -1120,90 +1855,87 @@ int reply_mknew(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, return(outsize); } + /**************************************************************************** - Reply to a create temporary file. + reply to a create temporary file ****************************************************************************/ - 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_buf(inbuf, fname, smb_buf(inbuf)+1, sizeof(fname), 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) { - set_bad_path_error(errno, bad_path); - 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) { + set_bad_path_error(errno, bad_path); + 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))) { - SCVAL(outbuf,smb_flg,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))) { + SCVAL(outbuf,smb_flg,CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED); + } - if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) - SCVAL(outbuf,smb_flg,CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED); + if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) + SCVAL(outbuf,smb_flg,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); } /******************************************************************* @@ -1256,7 +1988,7 @@ static NTSTATUS can_delete(char *fname,connection_struct *conn, int dirtype) if (!CAN_WRITE(conn)) return NT_STATUS_MEDIA_WRITE_PROTECTED; - if (conn->vfs_ops.lstat(conn,fname,&sbuf) != 0) + if (conn->vfs_ops.lstat(conn,dos_to_unix_static(fname),&sbuf) != 0) return NT_STATUS_OBJECT_NAME_NOT_FOUND; fmode = dos_mode(conn,fname,&sbuf); @@ -1266,6 +1998,7 @@ static NTSTATUS can_delete(char *fname,connection_struct *conn, int dirtype) if (fmode & aRONLY) return NT_STATUS_CANNOT_DELETE; } + if ((fmode & ~dirtype) & (aHIDDEN | aSYSTEM)) return NT_STATUS_CANNOT_DELETE; @@ -1304,12 +2037,12 @@ NTSTATUS unlink_internals(connection_struct *conn, int dirtype, char *name) 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,'/'); + + p = strrchr(name,'/'); if (!p) { pstrcpy(directory,"."); pstrcpy(mask,name); @@ -1318,7 +2051,7 @@ NTSTATUS unlink_internals(connection_struct *conn, int dirtype, char *name) pstrcpy(directory,name); pstrcpy(mask,p+1); } - + /* * We should only check the mangled cache * here if unix_convert failed. This means @@ -1327,59 +2060,60 @@ NTSTATUS unlink_internals(connection_struct *conn, int dirtype, char *name) * for a possible mangle. This patch from * Tine Smukavec <valentin.smukavec@hermes.si>. */ - + if (!rc && mangle_is_mangled(mask)) mangle_check_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; + if (!NT_STATUS_IS_OK(error)) + return error; - if (vfs_unlink(conn,directory) == 0) { + if (vfs_unlink(conn,directory) == 0) count++; - } } else { void *dirptr = NULL; char *dname; - - if (check_name(directory,conn)) - dirptr = OpenDir(conn, directory, True); - + 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 + 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,"*"); while ((dname = ReadDirName(dirptr))) { pstring fname; pstrcpy(fname,dname); - - if(!mask_match(fname, mask, case_sensitive)) continue; - + + 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++; + 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)) { + + if (count == 0 && NT_STATUS_IS_OK(error)) error = map_nt_error_from_unix(errno); - } - + return error; } @@ -1387,32 +2121,34 @@ NTSTATUS unlink_internals(connection_struct *conn, int dirtype, char *name) 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_buf(inbuf, name, smb_buf(inbuf) + 1, sizeof(name), STR_TERMINATE); - + + pstrcpy(name,smb_buf(inbuf) + 1); + 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); + if (!NT_STATUS_IS_OK(status)) + return ERROR_NT(status); /* * 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); @@ -1432,59 +2168,6 @@ void fail_readraw(void) } /**************************************************************************** - Use sendfile in readbraw. -****************************************************************************/ - -void send_file_readbraw(connection_struct *conn, files_struct *fsp, SMB_OFF_T startpos, size_t nread, - ssize_t mincount, char *outbuf) -{ - ssize_t ret=0; - -#if defined(WITH_SENDFILE) - /* - * We can only use sendfile on a non-chained packet and on a file - * that is exclusively oplocked. reply_readbraw has already checked the length. - */ - - if ((nread > 0) && (lp_write_cache_size(SNUM(conn)) == 0) && - EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type) && lp_use_sendfile(SNUM(conn)) ) { - DATA_BLOB header; - - _smb_setlen(outbuf,nread); - header.data = outbuf; - header.length = 4; - header.free = NULL; - - if ( conn->vfs_ops.sendfile( smbd_server_fd(), fsp, fsp->fd, &header, startpos, nread) == -1) { - /* - * Special hack for broken Linux with no 64 bit clean sendfile. If we - * return ENOSYS then pretend we just got a normal read. - */ - if (errno == ENOSYS) - goto normal_read; - - DEBUG(0,("send_file_readbraw: sendfile failed for file %s (%s). Terminating\n", - fsp->fsp_name, strerror(errno) )); - exit_server("send_file_readbraw sendfile failed"); - } - - } - - normal_read: -#endif - - if (nread > 0) { - ret = read_file(fsp,outbuf+4,startpos,nread); - if (ret < mincount) - ret = 0; - } - - _smb_setlen(outbuf,ret); - if (write_data(smbd_server_fd(),outbuf,4+ret) != 4+ret) - fail_readraw(); -} - -/**************************************************************************** Reply to a readbraw (core+ protocol). ****************************************************************************/ @@ -1494,6 +2177,7 @@ int reply_readbraw(connection_struct *conn, char *inbuf, char *outbuf, int dum_s size_t nread = 0; SMB_OFF_T startpos; char *header = outbuf; + ssize_t ret=0; files_struct *fsp; START_PROFILE(SMBreadbraw); @@ -1580,9 +2264,7 @@ int reply_readbraw(connection_struct *conn, char *inbuf, char *outbuf, int dum_s if (size < sizeneeded) { SMB_STRUCT_STAT st; if (vfs_fstat(fsp,fsp->fd,&st) == 0) - size = st.st_size; - if (!fsp->can_write) - fsp->size = size; + fsp->size = size = st.st_size; } if (startpos >= size) @@ -1597,288 +2279,217 @@ int reply_readbraw(connection_struct *conn, char *inbuf, char *outbuf, int dum_s DEBUG( 3, ( "readbraw fnum=%d start=%.0f max=%d min=%d nread=%d\n", fsp->fnum, (double)startpos, (int)maxcount, (int)mincount, (int)nread ) ); - send_file_readbraw(conn, fsp, startpos, nread, mincount, outbuf); + if (nread > 0) { + ret = read_file(fsp,header+4,startpos,nread); + if (ret < mincount) + ret = 0; + } + + _smb_setlen(header,ret); + if (write_data(smbd_server_fd(),header,4+ret) != 4+ret) + fail_readraw(); DEBUG(5,("readbraw finished\n")); END_PROFILE(SMBreadbraw); return -1; } + /**************************************************************************** - Reply to a lockread (core+ protocol). + 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; + 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); + 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. - */ - + 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_spin(fsp, conn, SVAL(inbuf,smb_pid), (SMB_BIG_UINT)numtoread, (SMB_BIG_UINT)startpos, WRITE_LOCK); if (NT_STATUS_V(status)) { - if (lp_blocking_locks(SNUM(conn)) && ERROR_WAS_LOCK_DENIED(status)) { - /* - * 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 (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; + } + END_PROFILE(SMBlockread); return ERROR_NT(status); - } + } - 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); } + /**************************************************************************** - Reply to a read. + reply to a read ****************************************************************************/ int reply_read(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize) { - size_t numtoread; - ssize_t nread = 0; - char *data; - SMB_OFF_T startpos; - int outsize = 0; - files_struct *fsp = file_fsp(inbuf,smb_vwv0); - START_PROFILE(SMBread); - - CHECK_FSP(fsp,conn); - CHECK_READ(fsp); - - 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); - } + size_t numtoread; + ssize_t nread = 0; + char *data; + SMB_OFF_T startpos; + int outsize = 0; + files_struct *fsp = file_fsp(inbuf,smb_vwv0); + START_PROFILE(SMBread); - if (numtoread > 0) - nread = read_file(fsp,data,startpos,numtoread); + CHECK_FSP(fsp,conn); + CHECK_READ(fsp); - if (nread < 0) { - END_PROFILE(SMBread); - return(UNIXERROR(ERRDOS,ERRnoaccess)); - } + numtoread = SVAL(inbuf,smb_vwv1); + startpos = IVAL(inbuf,smb_vwv2); - outsize += nread; - SSVAL(outbuf,smb_vwv0,nread); - SSVAL(outbuf,smb_vwv5,nread+3); - SCVAL(smb_buf(outbuf),0,1); - SSVAL(smb_buf(outbuf),1,nread); + outsize = set_message(outbuf,5,3,True); + numtoread = MIN(BUFFER_SIZE-outsize,numtoread); + data = smb_buf(outbuf) + 3; - DEBUG( 3, ( "read fnum=%d num=%d nread=%d\n", - fsp->fnum, (int)numtoread, (int)nread ) ); - - END_PROFILE(SMBread); - return(outsize); -} - -/**************************************************************************** - Reply to a read and X - possibly using sendfile. -****************************************************************************/ - -int send_file_readX(connection_struct *conn, char *inbuf,char *outbuf,int length, - files_struct *fsp, SMB_OFF_T startpos, size_t smb_maxcnt) -{ - ssize_t nread = -1; - char *data = smb_buf(outbuf); - -#if defined(WITH_SENDFILE) - /* - * We can only use sendfile on a non-chained packet and on a file - * that is exclusively oplocked. - */ - - if ((CVAL(inbuf,smb_vwv0) == 0xFF) && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type) && - lp_use_sendfile(SNUM(conn)) && (lp_write_cache_size(SNUM(conn)) == 0) ) { - SMB_STRUCT_STAT sbuf; - DATA_BLOB header; - - if(vfs_fstat(fsp,fsp->fd, &sbuf) == -1) - return(UNIXERROR(ERRDOS,ERRnoaccess)); - - if (startpos > sbuf.st_size) - goto normal_read; - - if (smb_maxcnt > (sbuf.st_size - startpos)) - smb_maxcnt = (sbuf.st_size - startpos); - - if (smb_maxcnt == 0) - goto normal_read; - - /* - * Set up the packet header before send. We - * assume here the sendfile will work (get the - * correct amount of data). - */ - - SSVAL(outbuf,smb_vwv5,smb_maxcnt); - SSVAL(outbuf,smb_vwv6,smb_offset(data,outbuf)); - SSVAL(smb_buf(outbuf),-2,smb_maxcnt); - SCVAL(outbuf,smb_vwv0,0xFF); - set_message(outbuf,12,smb_maxcnt,False); - header.data = outbuf; - header.length = data - outbuf; - header.free = NULL; - - if ( conn->vfs_ops.sendfile( smbd_server_fd(), fsp, fsp->fd, &header, startpos, smb_maxcnt) == -1) { - /* - * Special hack for broken Linux with no 64 bit clean sendfile. If we - * return ENOSYS then pretend we just got a normal read. - */ - if (errno == ENOSYS) - goto normal_read; - - DEBUG(0,("send_file_readX: sendfile failed for file %s (%s). Terminating\n", - fsp->fsp_name, strerror(errno) )); - exit_server("send_file_readX sendfile failed"); - } - - DEBUG( 3, ( "send_file_readX: sendfile fnum=%d max=%d nread=%d\n", - fsp->fnum, (int)smb_maxcnt, (int)nread ) ); - return -1; - } - - normal_read: - -#endif + if (is_locked(fsp,conn,(SMB_BIG_UINT)numtoread,(SMB_BIG_UINT)startpos, READ_LOCK,False)) { + END_PROFILE(SMBread); + return ERROR_DOS(ERRDOS,ERRlock); + } - nread = read_file(fsp,data,startpos,smb_maxcnt); + if (numtoread > 0) + nread = read_file(fsp,data,startpos,numtoread); - if (nread < 0) { - END_PROFILE(SMBreadX); - return(UNIXERROR(ERRDOS,ERRnoaccess)); - } - - SSVAL(outbuf,smb_vwv5,nread); - SSVAL(outbuf,smb_vwv6,smb_offset(data,outbuf)); - SSVAL(smb_buf(outbuf),-2,nread); + if (nread < 0) { + END_PROFILE(SMBread); + return(UNIXERROR(ERRDOS,ERRnoaccess)); + } + + outsize += nread; + SSVAL(outbuf,smb_vwv0,nread); + SSVAL(outbuf,smb_vwv5,nread+3); + SCVAL(smb_buf(outbuf),0,1); + SSVAL(smb_buf(outbuf),1,nread); - DEBUG( 3, ( "send_file_readX fnum=%d max=%d nread=%d\n", - fsp->fnum, (int)smb_maxcnt, (int)nread ) ); + DEBUG( 3, ( "read fnum=%d num=%d nread=%d\n", + fsp->fnum, (int)numtoread, (int)nread ) ); - return nread; + END_PROFILE(SMBread); + return(outsize); } + /**************************************************************************** - Reply to a read and X. + reply to a read and X ****************************************************************************/ - int reply_read_and_X(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize) { - files_struct *fsp = file_fsp(inbuf,smb_vwv2); - SMB_OFF_T startpos = IVAL(inbuf,smb_vwv3); - ssize_t nread = -1; - size_t smb_maxcnt = SVAL(inbuf,smb_vwv5); -#if 0 - size_t smb_mincnt = SVAL(inbuf,smb_vwv6); -#endif - - START_PROFILE(SMBreadX); + files_struct *fsp = file_fsp(inbuf,smb_vwv2); + SMB_OFF_T startpos = IVAL(inbuf,smb_vwv3); + size_t smb_maxcnt = SVAL(inbuf,smb_vwv5); + size_t smb_mincnt = SVAL(inbuf,smb_vwv6); + ssize_t nread = -1; + char *data; + START_PROFILE(SMBreadX); - /* If it's an IPC, pass off the pipe handler. */ - if (IS_IPC(conn)) { - END_PROFILE(SMBreadX); - return reply_pipe_read_and_X(inbuf,outbuf,length,bufsize); - } + /* If it's an IPC, pass off the pipe handler. */ + if (IS_IPC(conn)) { + END_PROFILE(SMBreadX); + return reply_pipe_read_and_X(inbuf,outbuf,length,bufsize); + } - CHECK_FSP(fsp,conn); - CHECK_READ(fsp); + CHECK_FSP(fsp,conn); + CHECK_READ(fsp); - set_message(outbuf,12,0,True); + set_message(outbuf,12,0,True); + data = smb_buf(outbuf); - if(CVAL(inbuf,smb_wct) == 12) { + if(CVAL(inbuf,smb_wct) == 12) { #ifdef LARGE_SMB_OFF_T - /* - * This is a large offset (64 bit) read. - */ - startpos |= (((SMB_OFF_T)IVAL(inbuf,smb_vwv10)) << 32); + /* + * This is a large offset (64 bit) read. + */ + startpos |= (((SMB_OFF_T)IVAL(inbuf,smb_vwv10)) << 32); #else /* !LARGE_SMB_OFF_T */ - /* - * Ensure we haven't been sent a >32 bit offset. - */ + /* + * Ensure we haven't been sent a >32 bit offset. + */ - if(IVAL(inbuf,smb_vwv10) != 0) { - DEBUG(0,("reply_read_and_X - large offset (%x << 32) used and we don't support \ + if(IVAL(inbuf,smb_vwv10) != 0) { + DEBUG(0,("reply_read_and_X - large offset (%x << 32) used and we don't support \ 64 bit offsets.\n", (unsigned int)IVAL(inbuf,smb_vwv10) )); - END_PROFILE(SMBreadX); - return ERROR_DOS(ERRDOS,ERRbadaccess); - } + END_PROFILE(SMBreadX); + return ERROR_DOS(ERRDOS,ERRbadaccess); + } #endif /* LARGE_SMB_OFF_T */ - } - - 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); - } + } - nread = send_file_readX(conn, inbuf, outbuf, length, fsp, startpos, smb_maxcnt); - if (nread != -1) - nread = chain_reply(inbuf,outbuf,length,bufsize); + 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); + } + nread = read_file(fsp,data,startpos,smb_maxcnt); + + if (nread < 0) { + END_PROFILE(SMBreadX); + return(UNIXERROR(ERRDOS,ERRnoaccess)); + } + + SSVAL(outbuf,smb_vwv5,nread); + SSVAL(outbuf,smb_vwv6,smb_offset(data,outbuf)); + SSVAL(smb_buf(outbuf),-2,nread); + + DEBUG( 3, ( "readX fnum=%d min=%d max=%d nread=%d\n", + fsp->fnum, (int)smb_mincnt, (int)smb_maxcnt, (int)nread ) ); - END_PROFILE(SMBreadX); - return nread; + END_PROFILE(SMBreadX); + return chain_reply(inbuf,outbuf,length,bufsize); } /**************************************************************************** - Reply to a writebraw (core+ or LANMAN1.0 protocol). + reply to a writebraw (core+ or LANMAN1.0 protocol) ****************************************************************************/ int reply_writebraw(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize) @@ -1993,15 +2604,12 @@ int reply_writebraw(connection_struct *conn, char *inbuf,char *outbuf, int size, /* we won't return a status if write through is not selected - this follows what WfWg does */ END_PROFILE(SMBwritebraw); if (!write_through && total_written==tcount) { - -#if RABBIT_PELLET_FIX /* * Fix for "rabbit pellet" mode, trigger an early TCP ack by * sending a SMBkeepalive. Thanks to DaveCB at Sun for this. JRA. */ if (!send_keepalive(smbd_server_fd())) exit_server("reply_writebraw: send of keepalive failed"); -#endif return(-1); } @@ -2009,68 +2617,68 @@ int reply_writebraw(connection_struct *conn, char *inbuf,char *outbuf, int size, } /**************************************************************************** - Reply to a writeunlock (core+). + 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; + 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); + 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); + END_PROFILE(SMBwriteunlock); return ERROR_DOS(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); + 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; + } + + 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); } + /**************************************************************************** Reply to a write. ****************************************************************************/ @@ -2149,10 +2757,10 @@ int reply_write(connection_struct *conn, char *inbuf,char *outbuf,int size,int d return(outsize); } + /**************************************************************************** - Reply to a write and X. + reply to a write and X ****************************************************************************/ - int reply_write_and_X(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize) { files_struct *fsp = file_fsp(inbuf,smb_vwv2); @@ -2249,8 +2857,9 @@ int reply_write_and_X(connection_struct *conn, char *inbuf,char *outbuf,int leng return chain_reply(inbuf,outbuf,length,bufsize); } + /**************************************************************************** - Reply to a lseek. + reply to a lseek ****************************************************************************/ int reply_lseek(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize) @@ -2341,22 +2950,21 @@ 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. + reply to a exit ****************************************************************************/ - int reply_exit(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize) { @@ -2370,16 +2978,15 @@ int reply_exit(connection_struct *conn, return(outsize); } + /**************************************************************************** Reply to a close - has to deal with closing a directory opened by NT SMB's. ****************************************************************************/ - int reply_close(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize) { int outsize = 0; time_t mtime; - int32 eclass = 0, err = 0; files_struct *fsp = NULL; START_PROFILE(SMBclose); @@ -2445,18 +3052,13 @@ 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); } + /**************************************************************************** - Reply to a writeclose (Core+ protocol). + reply to a writeclose (Core+ protocol) ****************************************************************************/ int reply_writeclose(connection_struct *conn, @@ -2513,10 +3115,10 @@ int reply_writeclose(connection_struct *conn, return(outsize); } + /**************************************************************************** - Reply to a lock. + reply to a lock ****************************************************************************/ - int reply_lock(connection_struct *conn, char *inbuf,char *outbuf, int length, int dum_buffsize) { @@ -2538,18 +3140,18 @@ int reply_lock(connection_struct *conn, status = do_lock_spin(fsp, conn, SVAL(inbuf,smb_pid), count, offset, WRITE_LOCK); if (NT_STATUS_V(status)) { - if (lp_blocking_locks(SNUM(conn)) && ERROR_WAS_LOCK_DENIED(status)) { - /* - * 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); + 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); } @@ -2557,41 +3159,40 @@ int reply_lock(connection_struct *conn, return(outsize); } + /**************************************************************************** - Reply to a unlock. + 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; + 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); + 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); - 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); + END_PROFILE(SMBunlock); return ERROR_NT(status); - } + } - 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); + 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); } + /**************************************************************************** - Reply to a tdis. + reply to a tdis ****************************************************************************/ - int reply_tdis(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize) { @@ -2615,10 +3216,11 @@ int reply_tdis(connection_struct *conn, return outsize; } + + /**************************************************************************** - Reply to a echo. + reply to a echo ****************************************************************************/ - int reply_echo(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize) { @@ -2656,10 +3258,10 @@ int reply_echo(connection_struct *conn, return -1; } + /**************************************************************************** - Reply to a printopen. + reply to a printopen ****************************************************************************/ - int reply_printopen(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize) { @@ -2690,8 +3292,9 @@ int reply_printopen(connection_struct *conn, return(outsize); } + /**************************************************************************** - Reply to a printclose. + reply to a printclose ****************************************************************************/ int reply_printclose(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize) @@ -2723,10 +3326,10 @@ int reply_printclose(connection_struct *conn, return(outsize); } + /**************************************************************************** - Reply to a printqueue. + reply to a printqueue ****************************************************************************/ - int reply_printqueue(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize) { @@ -2773,7 +3376,7 @@ int reply_printqueue(connection_struct *conn, SSVAL(p,5, queue[i].job); SIVAL(p,7,queue[i].size); SCVAL(p,11,0); - srvstr_push(outbuf, p+12, queue[i].fs_user, 16, STR_ASCII); + StrnCpy(p+12,queue[i].fs_user,16); p += 28; } @@ -2794,10 +3397,10 @@ int reply_printqueue(connection_struct *conn, return(outsize); } + /**************************************************************************** - Reply to a printwrite. + reply to a printwrite ****************************************************************************/ - int reply_printwrite(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize) { int numtowrite; @@ -2828,29 +3431,29 @@ int reply_printwrite(connection_struct *conn, char *inbuf,char *outbuf, int dum_ return(outsize); } + /**************************************************************************** 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) { 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) { NTSTATUS nterr = set_bad_path_error(errno, bad_path); if (!NT_STATUS_IS_OK(nterr)) return nterr; return map_nt_error_from_unix(errno); } - + return NT_STATUS_OK; } @@ -2865,7 +3468,7 @@ int reply_mkdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, NTSTATUS status; START_PROFILE(SMBmkdir); - srvstr_pull_buf(inbuf, directory, smb_buf(inbuf) + 1, sizeof(directory), STR_TERMINATE); + pstrcpy(directory,smb_buf(inbuf) + 1); RESOLVE_DFSPATH(directory, conn, inbuf, outbuf); @@ -2913,7 +3516,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_static(fullname), &st) != 0) { ret = True; break; } @@ -2932,6 +3535,7 @@ static BOOL recursive_rmdir(connection_struct *conn, char *directory) break; } } + CloseDir(dirptr); return ret; } @@ -2966,7 +3570,6 @@ BOOL rmdir_internals(connection_struct *conn, char *directory) break; } } - if(all_veto_files) { SeekDir(dirptr,dirpos); while ((dname = ReadDirName(dirptr))) { @@ -2981,12 +3584,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_static(fullname), &st) != 0) break; if(st.st_mode & S_IFDIR) { if(lp_recursive_veto_delete(SNUM(conn))) { @@ -3008,7 +3610,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))); @@ -3028,7 +3630,7 @@ int reply_rmdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, SMB_STRUCT_STAT sbuf; START_PROFILE(SMBrmdir); - srvstr_pull_buf(inbuf, directory, smb_buf(inbuf) + 1, sizeof(directory), STR_TERMINATE); + pstrcpy(directory,smb_buf(inbuf) + 1); RESOLVE_DFSPATH(directory, conn, inbuf, outbuf) @@ -3055,31 +3657,31 @@ int reply_rmdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, return(outsize); } + /******************************************************************* - Resolve wildcards in a filename rename. +resolve wildcards in a filename rename ********************************************************************/ - static BOOL resolve_wildcards(char *name1,char *name2) { fstring root1,root2; 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); @@ -3153,7 +3755,7 @@ NTSTATUS rename_internals(connection_struct *conn, char *name, char *newname, BO * as this is checked in resolve_wildcards(). */ - p = strrchr_m(name,'/'); + p = strrchr(name,'/'); if (!p) { pstrcpy(directory,"."); pstrcpy(mask,name); @@ -3179,6 +3781,9 @@ NTSTATUS rename_internals(connection_struct *conn, char *name, char *newname, BO has_wild = ms_has_wild(mask); if (!has_wild) { + pstring zdirectory; + pstring znewname; + /* * No wildcards - just process the one file. */ @@ -3189,7 +3794,7 @@ NTSTATUS rename_internals(connection_struct *conn, char *name, char *newname, BO pstrcat(directory,mask); /* Ensure newname contains a '/' also */ - if(strrchr_m(newname,'/') == 0) { + if(strrchr(newname,'/') == 0) { pstring tmpstr; pstrcpy(tmpstr, "./"); @@ -3198,7 +3803,7 @@ NTSTATUS rename_internals(connection_struct *conn, char *name, char *newname, BO } DEBUG(3,("rename_internals: case_sensitive = %d, case_preserve = %d, short case preserve = %d, \ -directory = %s, newname = %s, newname_last_component = %s, is_8_3 = %d\n", +directory = %s, newname = %s, newname_last_component = %s, mangle_is_8_3 = %d\n", case_sensitive, case_preserve, short_case_preserve, directory, newname, newname_last_component, is_short_name)); @@ -3223,7 +3828,7 @@ directory = %s, newname = %s, newname_last_component = %s, is_8_3 = %d\n", * 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, @@ -3235,9 +3840,10 @@ directory = %s, newname = %s, newname_last_component = %s, is_8_3 = %d\n", pstrcpy(p+1, newname_last_component); } } - + + resolve_wildcards(directory,newname); - + /* * The source object must exist. */ @@ -3252,7 +3858,7 @@ directory = %s, newname = %s, newname_last_component = %s, is_8_3 = %d\n", * directory existed or not. */ - p = strrchr_m(directory, '/'); + p = strrchr(directory, '/'); if (!p) return NT_STATUS_OBJECT_NAME_NOT_FOUND; *p = '\0'; @@ -3262,7 +3868,7 @@ directory = %s, newname = %s, newname_last_component = %s, is_8_3 = %d\n", } error = map_nt_error_from_unix(errno); DEBUG(3,("rename_internals: Error %s rename %s -> %s\n", - nt_errstr(error), directory,newname)); + get_nt_error_msg(error), directory,newname)); return error; } @@ -3271,16 +3877,19 @@ directory = %s, newname = %s, newname_last_component = %s, is_8_3 = %d\n", if (!NT_STATUS_IS_OK(error)) { DEBUG(3,("rename_internals: Error %s rename %s -> %s\n", - nt_errstr(error), directory,newname)); + get_nt_error_msg(error), directory,newname)); return error; } + pstrcpy(zdirectory, dos_to_unix_static(directory)); + pstrcpy(znewname, dos_to_unix_static(newname)); + /* * If the src and dest names are identical - including case, * don't do the rename, just return success. */ - if (strcsequal(directory, newname)) { + if (strcsequal(zdirectory, znewname)) { DEBUG(3,("rename_internals: identical names in rename %s - returning success\n", directory)); return NT_STATUS_OK; } @@ -3291,7 +3900,7 @@ directory = %s, newname = %s, newname_last_component = %s, is_8_3 = %d\n", return NT_STATUS_OBJECT_NAME_COLLISION; } - if(conn->vfs_ops.rename(conn,directory, newname) == 0) { + if(conn->vfs_ops.rename(conn,zdirectory, znewname) == 0) { DEBUG(3,("rename_internals: succeeded doing rename on %s -> %s\n", directory,newname)); return NT_STATUS_OK; @@ -3303,10 +3912,11 @@ directory = %s, newname = %s, newname_last_component = %s, is_8_3 = %d\n", error = map_nt_error_from_unix(errno); DEBUG(3,("rename_internals: Error %s rename %s -> %s\n", - nt_errstr(error), directory,newname)); + get_nt_error_msg(error), directory,newname)); return error; } else { + /* * Wildcards - process each file that matches. */ @@ -3335,12 +3945,12 @@ directory = %s, newname = %s, newname_last_component = %s, is_8_3 = %d\n", slprintf(fname,sizeof(fname)-1,"%s/%s",directory,dname); if (!vfs_object_exist(conn, fname, &sbuf1)) { error = NT_STATUS_OBJECT_NAME_NOT_FOUND; - DEBUG(6,("rename %s failed. Error %s\n", fname, nt_errstr(error))); + DEBUG(6,("rename %s failed. Error %s\n", fname, get_nt_error_msg(error))); continue; } error = can_rename(fname,conn,&sbuf1); if (!NT_STATUS_IS_OK(error)) { - DEBUG(6,("rename %s refused\n", fname)); + DEBUG(6,("rename %s failed. Error %s\n", fname, get_nt_error_msg(error))); continue; } pstrcpy(destname,newname); @@ -3352,20 +3962,21 @@ directory = %s, newname = %s, newname_last_component = %s, is_8_3 = %d\n", } if (!replace_if_exists && - vfs_file_exist(conn,destname, NULL)) { + vfs_object_exist(conn,destname, NULL)) { DEBUG(6,("file_exist %s\n", destname)); error = NT_STATUS_OBJECT_NAME_COLLISION; continue; } - if (!conn->vfs_ops.rename(conn,fname,destname)) + if (!conn->vfs_ops.rename(conn,dos_to_unix_static(fname), + dos_to_unix_static(destname))) count++; DEBUG(3,("rename_internals: doing rename on %s -> %s\n",fname,destname)); } CloseDir(dirptr); } } - + if (count == 0 && NT_STATUS_IS_OK(error)) { error = map_nt_error_from_unix(errno); } @@ -3377,27 +3988,22 @@ directory = %s, newname = %s, newname_last_component = %s, is_8_3 = %d\n", 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; - START_PROFILE(SMBmv); - p = smb_buf(inbuf) + 1; - p += srvstr_pull_buf(inbuf, name, p, sizeof(name), STR_TERMINATE); - p++; - p += srvstr_pull_buf(inbuf, newname, p, sizeof(newname), STR_TERMINATE); - + pstrcpy(name,smb_buf(inbuf) + 1); + pstrcpy(newname,smb_buf(inbuf) + 3 + strlen(name)); + 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); @@ -3406,7 +4012,7 @@ int reply_mv(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, /* * 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); @@ -3431,7 +4037,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 @@ -3493,10 +4099,11 @@ 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. -****************************************************************************/ + +/**************************************************************************** + reply to a file copy. + ****************************************************************************/ int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize) { int outsize = 0; @@ -3521,9 +4128,8 @@ int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, *directory = *mask = 0; - p = smb_buf(inbuf); - p += srvstr_pull_buf(inbuf, name, p, sizeof(name), STR_TERMINATE); - p += srvstr_pull_buf(inbuf, newname, p, sizeof(newname), STR_TERMINATE); + pstrcpy(name,smb_buf(inbuf)); + pstrcpy(newname,smb_buf(inbuf) + 1 + strlen(name)); DEBUG(3,("reply_copy : %s -> %s\n",name,newname)); @@ -3559,7 +4165,7 @@ int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, return ERROR_DOS(ERRSRV,ERRerror); } - p = strrchr_m(name,'/'); + p = strrchr(name,'/'); if (!p) { pstrcpy(directory,"./"); pstrcpy(mask,name); @@ -3579,7 +4185,7 @@ int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, */ if (!rc && mangle_is_mangled(mask)) - mangle_check_cache( mask ); + mangle_check_cache( mask ); has_wild = ms_has_wild(mask); @@ -3659,9 +4265,8 @@ int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, } /**************************************************************************** - Reply to a setdir. + reply to a setdir ****************************************************************************/ - int reply_setdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize) { int snum; @@ -3675,8 +4280,9 @@ int reply_setdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size END_PROFILE(pathworks_setdir); return ERROR_DOS(ERRDOS,ERRnoaccess); } - - srvstr_pull_buf(inbuf, newdir, smb_buf(inbuf) + 1, sizeof(newdir), STR_TERMINATE); + + pstrcpy(newdir,smb_buf(inbuf) + 1); + strlower(newdir); if (strlen(newdir) == 0) { ok = True; @@ -3835,7 +4441,7 @@ SMB_BIG_UINT get_lock_offset( char *data, int data_offset, BOOL large_file_forma } /**************************************************************************** - Reply to a lockingX request. + reply to a lockingX request ****************************************************************************/ int reply_lockingX(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize) @@ -3855,9 +4461,9 @@ int reply_lockingX(connection_struct *conn, char *inbuf,char *outbuf,int length, NTSTATUS status; START_PROFILE(SMBlockingX); - + CHECK_FSP(fsp,conn); - + data = smb_buf(inbuf); if (locktype & (LOCKING_ANDX_CANCEL_LOCK | LOCKING_ANDX_CHANGE_LOCKTYPE)) { @@ -3866,21 +4472,21 @@ int reply_lockingX(connection_struct *conn, char *inbuf,char *outbuf,int length, compatible! (tridge) */ return ERROR_NT(NT_STATUS_NOT_SUPPORTED); } - + /* Check if this is an oplock break on a file - we have granted an oplock on. + 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 )); + (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)); @@ -3897,16 +4503,16 @@ no oplock granted on this file (%s).\n", fsp->fnum, fsp->fsp_name)); if (remove_oplock(fsp, break_to_none) == False) { DEBUG(0,("reply_lockingX: error in removing oplock on file %s\n", - fsp->fsp_name )); + 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. */ + 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) )); + (unsigned int)CVAL(inbuf,smb_vwv0) )); END_PROFILE(SMBlockingX); return -1; } @@ -3916,16 +4522,16 @@ no oplock granted on this file (%s).\n", fsp->fnum, 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 */ + 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".... :-). */ @@ -3935,8 +4541,8 @@ no oplock granted on this file (%s).\n", fsp->fnum, fsp->fsp_name)); } 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 )); - + (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); @@ -3947,18 +4553,18 @@ no oplock granted on this file (%s).\n", fsp->fnum, fsp->fsp_name)); /* Setup the timeout in seconds. */ lock_timeout = ((lock_timeout == -1) ? -1 : (lock_timeout+999)/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 */ - + 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".... :-). */ @@ -3966,15 +4572,16 @@ no oplock granted on this file (%s).\n", fsp->fnum, fsp->fsp_name)); END_PROFILE(SMBlockingX); return ERROR_DOS(ERRDOS,ERRnoaccess); } - + DEBUG(10,("reply_lockingX: lock start=%.0f, len=%.0f for pid %u, file %s timeout = %d\n", - (double)offset, (double)count, (unsigned int)lock_pid, - fsp->fsp_name, (int)lock_timeout )); - + (double)offset, (double)count, (unsigned int)lock_pid, fsp->fsp_name, + (int)lock_timeout )); + status = do_lock_spin(fsp,conn,lock_pid, count,offset, - ((locktype & 1) ? READ_LOCK : WRITE_LOCK)); + ((locktype & 1) ? READ_LOCK : WRITE_LOCK)); + if (NT_STATUS_V(status)) { - if ((lock_timeout != 0) && lp_blocking_locks(SNUM(conn)) && ERROR_WAS_LOCK_DENIED(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 @@ -3988,10 +4595,10 @@ no oplock granted on this file (%s).\n", fsp->fnum, fsp->fsp_name)); 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) { + 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 @@ -4001,7 +4608,7 @@ no oplock granted on this file (%s).\n", fsp->fnum, fsp->fsp_name)); 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".... :-). */ @@ -4009,7 +4616,7 @@ no oplock granted on this file (%s).\n", fsp->fnum, fsp->fsp_name)); END_PROFILE(SMBlockingX); return ERROR_DOS(ERRDOS,ERRnoaccess); } - + do_unlock(fsp,conn,lock_pid,count,offset); } END_PROFILE(SMBlockingX); @@ -4017,16 +4624,18 @@ no oplock granted on this file (%s).\n", fsp->fnum, fsp->fsp_name)); } 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 ) ); - + 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) @@ -4053,6 +4662,7 @@ int reply_readbmpx(connection_struct *conn, char *inbuf,char *outbuf,int length, CHECK_FSP(fsp,conn); CHECK_READ(fsp); + CHECK_ERROR(fsp); startpos = IVAL(inbuf,smb_vwv1); maxcount = SVAL(inbuf,smb_vwv3); @@ -4067,14 +4677,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); } do { size_t N = MIN(max_per_packet,tcount-total_read); - + nread = read_file(fsp,data,startpos,N); if (nread <= 0) @@ -4122,7 +4732,6 @@ int reply_setattrE(connection_struct *conn, char *inbuf,char *outbuf, int size, * 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); @@ -4219,6 +4828,7 @@ 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); @@ -4237,11 +4847,11 @@ int reply_writebmpx(connection_struct *conn, char *inbuf,char *outbuf, int size, SCVAL(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 */ @@ -4316,8 +4926,7 @@ int reply_writebs(connection_struct *conn, char *inbuf,char *outbuf, int dum_siz if (nwritten < (ssize_t)numtowrite) { if(write_through) { /* We are returning an error - we can delete the aux struct */ - if (wbms) - free((char *)wbms); + SAFE_FREE(wbms); fsp->wbmpx_ptr = NULL; END_PROFILE(SMBwriteBs); return(ERROR_DOS(ERRHRD,ERRdiskfull)); @@ -4336,7 +4945,7 @@ int reply_writebs(connection_struct *conn, char *inbuf,char *outbuf, int dum_siz send_response = True; } - free((char *)wbms); + SAFE_FREE(wbms); fsp->wbmpx_ptr = NULL; } @@ -4368,7 +4977,8 @@ int reply_getattrE(connection_struct *conn, char *inbuf,char *outbuf, int size, return ERROR_DOS(ERRDOS,ERRbadfid); } - /* Do an fstat on this file */ + /* Do an stat on this file */ + if(fsp_stat(fsp, &sbuf)) { END_PROFILE(SMBgetattrE); return(UNIXERROR(ERRDOS,ERRnoaccess)); @@ -4376,8 +4986,7 @@ int reply_getattrE(connection_struct *conn, char *inbuf,char *outbuf, int size, mode = dos_mode(conn,fsp->fsp_name,&sbuf); - /* - * Convert the times into dos times. Set create + /* Convert the times into dos times. Set create * date to be last modify date as UNIX doesn't save * this. */ @@ -4385,7 +4994,6 @@ int reply_getattrE(connection_struct *conn, char *inbuf,char *outbuf, int size, put_dos_date2(outbuf,smb_vwv0,get_create_time(&sbuf,lp_fake_dir_create_times(SNUM(conn)))); put_dos_date2(outbuf,smb_vwv2,sbuf.st_atime); put_dos_date2(outbuf,smb_vwv4,sbuf.st_mtime); - if (mode & aDIR) { SIVAL(outbuf,smb_vwv6,0); SIVAL(outbuf,smb_vwv8,0); |