#include "libsmb/nmblib.h"
#include "auth.h"
#include "smbprofile.h"
+#include "../lib/tsocket/tsocket.h"
/****************************************************************************
Ensure we check the path in *exactly* the same way as W2K for a findfirst/findnext
char **pp_dest, const char *src, int flags,
NTSTATUS *err, bool *contains_wcard)
{
- return srvstr_get_path_wcard(mem_ctx, (char *)req->inbuf, req->flags2,
+ return srvstr_get_path_wcard(mem_ctx, (const char *)req->inbuf, req->flags2,
pp_dest, src, smbreq_bufrem(req, src),
flags, err, contains_wcard);
}
p = strchr_m(retarget, '#');
if (p != NULL) {
*p++ = '\0';
- sscanf(p, "%x", &retarget_type);
+ if (sscanf(p, "%x", &retarget_type) != 1) {
+ goto fail;
+ }
}
ret = resolve_name(retarget, &retarget_addr, retarget_type, false);
if (!srv_send_smb(sconn, (char *)outbuf, false, 0, false,
NULL)) {
- exit_server_cleanly("netbios_session_regarget: srv_send_smb "
+ exit_server_cleanly("netbios_session_retarget: srv_send_smb "
"failed.");
}
return ret;
}
+static void reply_called_name_not_present(char *outbuf)
+{
+ smb_setlen(outbuf, 1);
+ SCVAL(outbuf, 0, 0x83);
+ SCVAL(outbuf, 4, 0x82);
+}
+
/****************************************************************************
Reply to a (netbios-level) special message.
****************************************************************************/
smb_setlen(outbuf,0);
switch (msg_type) {
- case 0x81: /* session request */
+ case NBSSrequest: /* session request */
{
/* inbuf_size is guarenteed to be at least 4. */
fstring name1,name2;
exit_server_cleanly("multiple session request not permitted");
}
- SCVAL(outbuf,0,0x82);
+ SCVAL(outbuf,0,NBSSpositive);
SCVAL(outbuf,3,0);
/* inbuf_size is guaranteed to be at least 4. */
name_len1 = name_len((unsigned char *)(inbuf+4),inbuf_size - 4);
if (name_len1 <= 0 || name_len1 > inbuf_size - 4) {
DEBUG(0,("Invalid name length in session request\n"));
+ reply_called_name_not_present(outbuf);
break;
}
name_len2 = name_len((unsigned char *)(inbuf+4+name_len1),inbuf_size - 4 - name_len1);
if (name_len2 <= 0 || name_len2 > inbuf_size - 4 - name_len1) {
DEBUG(0,("Invalid name length in session request\n"));
+ reply_called_name_not_present(outbuf);
break;
}
if (name_type1 == -1 || name_type2 == -1) {
DEBUG(0,("Invalid name type in session request\n"));
+ reply_called_name_not_present(outbuf);
break;
}
*/
if (strequal(name1, "*SMBSERVER ")
|| strequal(name1, "*SMBSERV ")) {
- fstrcpy(name1, sconn->client_id.addr);
+ char *raddr;
+
+ raddr = tsocket_address_inet_addr_string(sconn->remote_address,
+ talloc_tos());
+ if (raddr == NULL) {
+ exit_server_cleanly("could not allocate raddr");
+ }
+
+ fstrcpy(name1, raddr);
}
set_local_machine_name(name1, True);
if (name_type2 == 'R') {
/* We are being asked for a pathworks session ---
no thanks! */
- SCVAL(outbuf, 0,0x83);
+ reply_called_name_not_present(outbuf);
break;
}
case 0x89: /* session keepalive request
(some old clients produce this?) */
- SCVAL(outbuf,0,SMBkeepalive);
+ SCVAL(outbuf,0,NBSSkeepalive);
SCVAL(outbuf,3,0);
break;
- case 0x82: /* positive session response */
- case 0x83: /* negative session response */
- case 0x84: /* retarget session response */
+ case NBSSpositive: /* positive session response */
+ case NBSSnegative: /* negative session response */
+ case NBSSretarget: /* retarget session response */
DEBUG(0,("Unexpected session response\n"));
break;
- case SMBkeepalive: /* session keepalive */
+ case NBSSkeepalive: /* session keepalive */
default:
return;
}
msg_type, msg_flags));
srv_send_smb(sconn, outbuf, false, 0, false, NULL);
+
+ if (CVAL(outbuf, 0) != 0x82) {
+ exit_server_cleanly("invalid netbios session");
+ }
return;
}
perm1 = FILE_ALL_ACCESS;
perm2 = FILE_ALL_ACCESS;
} else {
- perm1 = CAN_WRITE(conn) ?
- SHARE_ALL_ACCESS :
- SHARE_READ_ONLY;
+ perm1 = conn->share_access;
}
SIVAL(req->outbuf, smb_vwv3, perm1);
service));
/* set the incoming and outgoing tid to the just created one */
- SSVAL(req->inbuf,smb_tid,conn->cnum);
+ SSVAL(discard_const_p(uint8_t, req->inbuf),smb_tid,conn->cnum);
SSVAL(req->outbuf,smb_tid,conn->cnum);
END_PROFILE(SMBtconX);
SSVAL(p, 0, 0);
}
srvstr_push((char *)req->outbuf, req->flags2, p+2,
- global_myname(), 15,
+ lp_netbios_name(), 15,
STR_TERMINATE|STR_ASCII);
if (conn) {
srvstr_push((char *)req->outbuf, req->flags2,
/* dos smetimes asks for a stat of "" - it returns a "hidden directory"
under WfWg - weird! */
if (*fname == '\0') {
- mode = aHIDDEN | aDIR;
+ mode = FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY;
if (!CAN_WRITE(conn)) {
- mode |= aRONLY;
+ mode |= FILE_ATTRIBUTE_READONLY;
}
size = 0;
mtime = 0;
}
mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
- if (mode & aDIR) {
+ if (mode & FILE_ATTRIBUTE_DIRECTORY) {
size = 0;
}
}
mode = SVAL(req->vwv+0, 0);
mtime = srv_make_unix_date3(req->vwv+1);
- ft.mtime = convert_time_t_to_timespec(mtime);
- status = smb_set_file_time(conn, NULL, smb_fname, &ft, true);
- if (!NT_STATUS_IS_OK(status)) {
- reply_nterror(req, status);
- goto out;
- }
-
if (mode != FILE_ATTRIBUTE_NORMAL) {
if (VALID_STAT_OF_DIR(smb_fname->st))
- mode |= aDIR;
+ mode |= FILE_ATTRIBUTE_DIRECTORY;
else
- mode &= ~aDIR;
+ mode &= ~FILE_ATTRIBUTE_DIRECTORY;
+
+ status = check_access(conn, NULL, smb_fname,
+ FILE_WRITE_ATTRIBUTES);
+ if (!NT_STATUS_IS_OK(status)) {
+ reply_nterror(req, status);
+ goto out;
+ }
if (file_set_dosmode(conn, smb_fname, mode, NULL,
false) != 0) {
}
}
+ ft.mtime = convert_time_t_to_timespec(mtime);
+ status = smb_set_file_time(conn, NULL, smb_fname, &ft, true);
+ if (!NT_STATUS_IS_OK(status)) {
+ reply_nterror(req, status);
+ goto out;
+ }
+
reply_outbuf(req, 0, 0);
DEBUG(3, ("setatr name=%s mode=%d\n", smb_fname_str_dbg(smb_fname),
status_len = SVAL(p, 0);
p += 2;
- /* dirtype &= ~aDIR; */
+ /* dirtype &= ~FILE_ATTRIBUTE_DIRECTORY; */
if (status_len == 0) {
nt_status = filename_convert(ctx, conn,
/* Initialize per SMBsearch/SMBffirst/SMBfunique operation data */
dptr_init_search_op(dirptr);
- if ((dirtype&0x1F) == aVOLID) {
+ if ((dirtype&0x1F) == FILE_ATTRIBUTE_VOLUME) {
char buf[DIR_STRUCT_SIZE];
memcpy(buf,status,21);
if (!make_dir_struct(ctx,buf,"???????????",volume_label(SNUM(conn)),
- 0,aVOLID,0,!allow_long_path_components)) {
+ 0,FILE_ATTRIBUTE_VOLUME,0,!allow_long_path_components)) {
reply_nterror(req, NT_STATUS_NO_MEMORY);
goto out;
}
goto out;
}
- if (!map_open_params_to_ntcreate(smb_fname, deny_mode,
+ if (!map_open_params_to_ntcreate(smb_fname->base_name, deny_mode,
OPENX_FILE_EXISTS_OPEN, &access_mask,
&share_mode, &create_disposition,
&create_options, &private_flags)) {
&info); /* pinfo */
if (!NT_STATUS_IS_OK(status)) {
- if (open_was_deferred(req->mid)) {
+ if (open_was_deferred(req->sconn, req->mid)) {
/* We have re-scheduled this call. */
goto out;
}
mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
- if (fattr & aDIR) {
+ if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
DEBUG(3,("attempt to open a directory %s\n",
fsp_str_dbg(fsp)));
close_file(req, fsp, ERROR_CLOSE);
goto out;
}
- if (!map_open_params_to_ntcreate(smb_fname, deny_mode, smb_ofun,
+ if (!map_open_params_to_ntcreate(smb_fname->base_name, deny_mode,
+ smb_ofun,
&access_mask, &share_mode,
&create_disposition,
&create_options,
&smb_action); /* pinfo */
if (!NT_STATUS_IS_OK(status)) {
- if (open_was_deferred(req->mid)) {
+ if (open_was_deferred(req->sconn, req->mid)) {
/* We have re-scheduled this call. */
goto out;
}
fattr = dos_mode(conn, fsp->fsp_name);
mtime = convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_mtime);
- if (fattr & aDIR) {
+ if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
close_file(req, fsp, ERROR_CLOSE);
reply_nterror(req, NT_STATUS_ACCESS_DENIED);
goto out;
goto out;
}
- if (fattr & aVOLID) {
+ if (fattr & FILE_ATTRIBUTE_VOLUME) {
DEBUG(0,("Attempt to create file (%s) with volid set - "
"please report this\n",
smb_fname_str_dbg(smb_fname)));
NULL); /* pinfo */
if (!NT_STATUS_IS_OK(status)) {
- if (open_was_deferred(req->mid)) {
+ if (open_was_deferred(req->sconn, req->mid)) {
/* We have re-scheduled this call. */
goto out;
}
close(tmpfd);
if (!NT_STATUS_IS_OK(status)) {
- if (open_was_deferred(req->mid)) {
+ if (open_was_deferred(req->sconn, req->mid)) {
/* We have re-scheduled this call. */
goto out;
}
static NTSTATUS can_rename(connection_struct *conn, files_struct *fsp,
uint16 dirtype)
{
- uint32 fmode;
-
if (!CAN_WRITE(conn)) {
return NT_STATUS_MEDIA_WRITE_PROTECTED;
}
- fmode = dos_mode(conn, fsp->fsp_name);
- if ((fmode & ~dirtype) & (aHIDDEN | aSYSTEM)) {
- return NT_STATUS_NO_SUCH_FILE;
+ if ((dirtype & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) !=
+ (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) {
+ /* Only bother to read the DOS attribute if we might deny the
+ rename on the grounds of attribute missmatch. */
+ uint32_t fmode = dos_mode(conn, fsp->fsp_name);
+ if ((fmode & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) {
+ return NT_STATUS_NO_SUCH_FILE;
+ }
}
if (S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
fattr = dos_mode(conn, smb_fname);
if (dirtype & FILE_ATTRIBUTE_NORMAL) {
- dirtype = aDIR|aARCH|aRONLY;
+ dirtype = FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY;
}
- dirtype &= (aDIR|aARCH|aRONLY|aHIDDEN|aSYSTEM);
+ dirtype &= (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM);
if (!dirtype) {
return NT_STATUS_NO_SUCH_FILE;
}
if (!dir_check_ftype(conn, fattr, dirtype)) {
- if (fattr & aDIR) {
+ if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
return NT_STATUS_FILE_IS_A_DIRECTORY;
}
return NT_STATUS_NO_SUCH_FILE;
}
/* Can't delete a directory. */
- if (fattr & aDIR) {
+ if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
return NT_STATUS_FILE_IS_A_DIRECTORY;
}
#endif
#if 0 /* JRATEST */
- else if (dirtype & aDIR) /* Asked for a directory and it isn't. */
+ else if (dirtype & FILE_ATTRIBUTE_DIRECTORY) /* Asked for a directory and it isn't. */
return NT_STATUS_OBJECT_NAME_INVALID;
#endif /* JRATEST */
}
/* The set is across all open files on this dev/inode pair. */
- if (!set_delete_on_close(fsp, True, &conn->session_info->utok)) {
+ if (!set_delete_on_close(fsp, True, conn->session_info->unix_token)) {
close_file(req, fsp, NORMAL_CLOSE);
return NT_STATUS_ACCESS_DENIED;
}
const char *dname = NULL;
char *talloced = NULL;
- if ((dirtype & SAMBA_ATTRIBUTES_MASK) == aDIR) {
+ if ((dirtype & SAMBA_ATTRIBUTES_MASK) == FILE_ATTRIBUTE_DIRECTORY) {
status = NT_STATUS_OBJECT_NAME_INVALID;
goto out;
}
status = unlink_internals(conn, req, dirtype, smb_fname,
path_contains_wcard);
if (!NT_STATUS_IS_OK(status)) {
- if (open_was_deferred(req->mid)) {
+ if (open_was_deferred(req->sconn, req->mid)) {
/* We have re-scheduled this call. */
goto out;
}
normal_readbraw:
- outbuf = TALLOC_ARRAY(NULL, char, nread+4);
+ outbuf = talloc_array(NULL, char, nread+4);
if (!outbuf) {
- DEBUG(0,("send_file_readbraw: TALLOC_ARRAY failed for size %u.\n",
+ DEBUG(0,("send_file_readbraw: talloc_array failed for size %u.\n",
(unsigned)(nread+4)));
reply_readbraw_error(sconn);
return;
START_PROFILE(SMBreadbraw);
if (srv_is_signing_active(sconn) ||
- is_encrypted_packet(req->inbuf)) {
+ is_encrypted_packet(sconn, req->inbuf)) {
exit_server_cleanly("reply_readbraw: SMB signing/sealing is active - "
"raw reads/writes are disallowed.");
}
"(%x << 32) used and we don't support "
"64 bit offsets.\n",
(unsigned int)IVAL(req->vwv+8, 0) ));
- reply_readbraw_error();
+ reply_readbraw_error(sconn);
END_PROFILE(SMBreadbraw);
return;
}
*/
if (!req_is_in_chain(req) &&
- !is_encrypted_packet(req->inbuf) && (fsp->base_fsp == NULL) &&
+ !is_encrypted_packet(req->sconn, req->inbuf) &&
+ (fsp->base_fsp == NULL) &&
(fsp->wcp == NULL) &&
lp_use_sendfile(SNUM(conn), req->sconn->smb1.signing_state) ) {
uint8 headerbuf[smb_size + 12 * 2];
void reply_read_and_X(struct smb_request *req)
{
+ struct smbd_server_connection *sconn = req->sconn;
connection_struct *conn = req->conn;
files_struct *fsp;
SMB_OFF_T startpos;
return;
}
- if (global_client_caps & CAP_LARGE_READX) {
+ if ((sconn->smb1.unix_info.client_cap_low & CIFS_UNIX_LARGE_READ_CAP) ||
+ (get_remote_arch() == RA_SAMBA)) {
+ /*
+ * This is Samba only behavior (up to Samba 3.6)!
+ *
+ * Windows 2008 R2 ignores the upper_size,
+ * so we do unless unix extentions are active
+ * or "smbclient" is talking to us.
+ */
size_t upper_size = SVAL(req->vwv+7, 0);
smb_maxcnt |= (upper_size<<16);
if (upper_size > 1) {
}
/* We currently don't do this on signed or sealed data. */
if (srv_is_signing_active(req->sconn) ||
- is_encrypted_packet(req->inbuf)) {
+ is_encrypted_packet(req->sconn, req->inbuf)) {
reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
END_PROFILE(SMBreadX);
return;
static NTSTATUS read_smb_length(int fd, char *inbuf, unsigned int timeout,
size_t *len)
{
- uint8_t msgtype = SMBkeepalive;
+ uint8_t msgtype = NBSSkeepalive;
- while (msgtype == SMBkeepalive) {
+ while (msgtype == NBSSkeepalive) {
NTSTATUS status;
status = read_smb_length_return_keepalive(fd, inbuf, timeout,
size_t numtowrite=0;
size_t tcount;
SMB_OFF_T startpos;
- char *data=NULL;
+ const char *data=NULL;
bool write_through;
files_struct *fsp;
struct lock_struct lock;
* type of SMBwritec, not SMBwriteBraw, as this tells the client
* we're finished.
*/
- SCVAL(req->inbuf,smb_com,SMBwritec);
+ SCVAL(discard_const_p(uint8_t, req->inbuf),smb_com,SMBwritec);
if (srv_is_signing_active(req->sconn)) {
END_PROFILE(SMBwritebraw);
on whether we are using the core+ or lanman1.0 protocol */
if(get_Protocol() <= PROTOCOL_COREPLUS) {
- numtowrite = SVAL(smb_buf(req->inbuf),-2);
- data = smb_buf(req->inbuf);
+ numtowrite = SVAL(smb_buf_const(req->inbuf),-2);
+ data = smb_buf_const(req->inbuf);
} else {
numtowrite = SVAL(req->vwv+10, 0);
data = smb_base(req->inbuf) + SVAL(req->vwv+11, 0);
total_written = nwritten;
/* Allocate a buffer of 64k + length. */
- buf = TALLOC_ARRAY(NULL, char, 65540);
+ buf = talloc_array(NULL, char, 65540);
if (!buf) {
reply_nterror(req, NT_STATUS_NO_MEMORY);
error_to_writebrawerr(req);
#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.
+ * sending a NBSSkeepalive. Thanks to DaveCB at Sun for this.
* JRA.
*/
if (!send_keepalive(req->sconn->sock)) {
unsigned int doff = 0;
size_t len = smb_len_large(inbuf);
- if (is_encrypted_packet(inbuf)) {
+ if (is_encrypted_packet(sconn, inbuf)) {
/* Can't do this on encrypted
* connections. */
return false;
ssize_t nwritten;
unsigned int smb_doff;
unsigned int smblen;
- char *data;
+ const char *data;
NTSTATUS status;
int saved_errno = 0;
status = rpc_pipe_open_interface(conn,
&ndr_table_spoolss.syntax_id,
conn->session_info,
- &conn->sconn->client_id,
+ conn->sconn->remote_address,
conn->sconn->msg_ctx,
&cli);
if (!NT_STATUS_IS_OK(status)) {
&info); /* pinfo */
if (!NT_STATUS_IS_OK(status)) {
- if (open_was_deferred(req->mid)) {
+ if (open_was_deferred(req->sconn, req->mid)) {
/* We have re-scheduled this call. */
goto out;
}
goto out;
}
- if (!set_delete_on_close(fsp, true, &conn->session_info->utok)) {
+ if (!set_delete_on_close(fsp, true, conn->session_info->unix_token)) {
close_file(req, fsp, ERROR_CLOSE);
reply_nterror(req, NT_STATUS_ACCESS_DENIED);
goto out;
files_struct *fsp;
bool did_rename = False;
NTSTATUS status;
- uint32_t new_name_hash;
+ uint32_t new_name_hash = 0;
for(fsp = file_find_di_first(conn->sconn, lck->id); fsp;
fsp = file_find_di_next(fsp)) {
TALLOC_FREE(parent_dir_dst);
}
+/****************************************************************************
+ Returns an error if the parent directory for a filename is open in an
+ incompatible way.
+****************************************************************************/
+
+static NTSTATUS parent_dirname_compatible_open(connection_struct *conn,
+ const struct smb_filename *smb_fname_dst_in)
+{
+ char *parent_dir = NULL;
+ struct smb_filename smb_fname_parent;
+ struct file_id id;
+ files_struct *fsp = NULL;
+ int ret;
+
+ if (!parent_dirname(talloc_tos(), smb_fname_dst_in->base_name,
+ &parent_dir, NULL)) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ ZERO_STRUCT(smb_fname_parent);
+ smb_fname_parent.base_name = parent_dir;
+
+ ret = SMB_VFS_LSTAT(conn, &smb_fname_parent);
+ if (ret == -1) {
+ return map_nt_error_from_unix(errno);
+ }
+
+ /*
+ * We're only checking on this smbd here, mostly good
+ * enough.. and will pass tests.
+ */
+
+ id = vfs_file_id_from_sbuf(conn, &smb_fname_parent.st);
+ for (fsp = file_find_di_first(conn->sconn, id); fsp;
+ fsp = file_find_di_next(fsp)) {
+ if (fsp->access_mask & DELETE_ACCESS) {
+ return NT_STATUS_SHARING_VIOLATION;
+ }
+ }
+ return NT_STATUS_OK;
+}
+
/****************************************************************************
Rename an open file - given an fsp.
****************************************************************************/
return status;
}
+ status = parent_dirname_compatible_open(conn, smb_fname_dst_in);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
/* Make a copy of the dst smb_fname structs */
status = copy_smb_filename(ctx, smb_fname_dst_in, &smb_fname_dst);
/* Quick check for "." and ".." */
if (ISDOT(dname) || ISDOTDOT(dname)) {
- if (attrs & aDIR) {
+ if (attrs & FILE_ATTRIBUTE_DIRECTORY) {
sysdir_entry = True;
} else {
TALLOC_FREE(talloced);
attrs, False, src_has_wcard, dest_has_wcard,
DELETE_ACCESS);
if (!NT_STATUS_IS_OK(status)) {
- if (open_was_deferred(req->mid)) {
+ if (open_was_deferred(req->sconn, req->mid)) {
/* We have re-scheduled this call. */
goto out;
}
if (!target_is_directory && count) {
new_create_disposition = FILE_OPEN;
} else {
- if (!map_open_params_to_ntcreate(smb_fname_dst_tmp, 0, ofun,
+ if (!map_open_params_to_ntcreate(smb_fname_dst_tmp->base_name,
+ 0, ofun,
NULL, NULL,
&new_create_disposition,
NULL,
goto out;
}
+ if (!(fsp->access_mask & FILE_WRITE_ATTRIBUTES)) {
+ reply_nterror(req, NT_STATUS_ACCESS_DENIED);
+ goto out;
+ }
+
status = smb_set_file_time(conn, fsp, fsp->fsp_name, &ft, true);
if (!NT_STATUS_IS_OK(status)) {
reply_nterror(req, status);
srv_put_dos_date2((char *)req->outbuf, smb_vwv4,
convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_mtime));
- if (mode & aDIR) {
+ if (mode & FILE_ATTRIBUTE_DIRECTORY) {
SIVAL(req->outbuf, smb_vwv6, 0);
SIVAL(req->outbuf, smb_vwv8, 0);
} else {