X-Git-Url: http://git.samba.org/samba.git/?p=kai%2Fsamba-autobuild%2F.git;a=blobdiff_plain;f=source3%2Fsmbd%2Fnttrans.c;h=0cc05dbd52ef17ebf19c14f1f8506802aad528ea;hp=204cdf9e3109b79b3d1540d15066dd3254718164;hb=7c51fa6d699a653cafa90df8e44911b576118ebd;hpb=5302db632660de44129d7cf48073bf52c9b27eca diff --git a/source3/smbd/nttrans.c b/source3/smbd/nttrans.c index 204cdf9e310..0cc05dbd52e 100644 --- a/source3/smbd/nttrans.c +++ b/source3/smbd/nttrans.c @@ -58,6 +58,8 @@ void send_nt_replies(connection_struct *conn, int params_sent_thistime, data_sent_thistime, total_sent_thistime; int alignment_offset = 3; int data_alignment_offset = 0; + struct smbd_server_connection *sconn = smbd_server_conn; + int max_send = sconn->smb1.sessions.max_send; /* * If there genuinely are no parameters or data to send just send @@ -66,7 +68,20 @@ void send_nt_replies(connection_struct *conn, if(params_to_send == 0 && data_to_send == 0) { reply_outbuf(req, 18, 0); + if (NT_STATUS_V(nt_error)) { + error_packet_set((char *)req->outbuf, + 0, 0, nt_error, + __LINE__,__FILE__); + } show_msg((char *)req->outbuf); + if (!srv_send_smb(smbd_server_fd(), + (char *)req->outbuf, + true, req->seqnum+1, + IS_CONN_ENCRYPTED(conn), + &req->pcd)) { + exit_server_cleanly("send_nt_replies: srv_send_smb failed."); + } + TALLOC_FREE(req->outbuf); return; } @@ -256,53 +271,6 @@ void send_nt_replies(connection_struct *conn, } } -/**************************************************************************** - Is it an NTFS stream name ? - An NTFS file name is .:: - $DATA can be used as both a stream name and a stream type. A missing stream - name or type implies $DATA. - - Both Windows stream names and POSIX files can contain the ':' character. - This function first checks for the existence of a colon in the last component - of the given name. If the name contains a colon we differentiate between a - stream and POSIX file by checking if the latter exists through a POSIX stat. - - Function assumes we've already chdir() to the "root" directory of fname. -****************************************************************************/ - -bool is_ntfs_stream_name(const char *fname) -{ - const char *lastcomp; - SMB_STRUCT_STAT sbuf; - - /* If all pathnames are treated as POSIX we ignore streams. */ - if (lp_posix_pathnames()) { - return false; - } - - /* Find the last component of the name. */ - if ((lastcomp = strrchr_m(fname, '/')) != NULL) - ++lastcomp; - else - lastcomp = fname; - - /* If there is no colon in the last component, it's not a stream. */ - if (strchr_m(lastcomp, ':') == NULL) - return false; - - /* - * If file already exists on disk, it's not a stream. The stat must - * bypass the vfs layer so streams modules don't intefere. - */ - if (sys_stat(fname, &sbuf) == 0) { - DEBUG(5, ("is_ntfs_stream_name: file %s contains a ':' but is " - "not a stream\n", fname)); - return false; - } - - return true; -} - /**************************************************************************** Reply to an NT create and X call on a pipe ****************************************************************************/ @@ -414,6 +382,7 @@ static void do_ntcreate_pipe_open(connection_struct *conn, void reply_ntcreate_and_X(struct smb_request *req) { connection_struct *conn = req->conn; + struct smb_filename *smb_fname = NULL; char *fname = NULL; uint32 flags; uint32 access_mask; @@ -427,13 +396,14 @@ void reply_ntcreate_and_X(struct smb_request *req) reply bits separately. */ uint32 fattr=0; SMB_OFF_T file_len = 0; - SMB_STRUCT_STAT sbuf; int info = 0; files_struct *fsp = NULL; char *p = NULL; + struct timespec create_timespec; struct timespec c_timespec; struct timespec a_timespec; struct timespec m_timespec; + struct timespec write_time_ts; NTSTATUS status; int oplock_request; uint8_t oplock_granted = NO_OPLOCK_RETURN; @@ -441,8 +411,6 @@ void reply_ntcreate_and_X(struct smb_request *req) START_PROFILE(SMBntcreateX); - SET_STAT_INVALID(sbuf); - if (req->wct < 24) { reply_nterror(req, NT_STATUS_INVALID_PARAMETER); return; @@ -466,8 +434,7 @@ void reply_ntcreate_and_X(struct smb_request *req) if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); - END_PROFILE(SMBntcreateX); - return; + goto out; } DEBUG(10,("reply_ntcreate_and_X: flags = 0x%x, access_mask = 0x%x " @@ -496,12 +463,10 @@ void reply_ntcreate_and_X(struct smb_request *req) if (IS_IPC(conn)) { if (lp_nt_pipe_support()) { do_ntcreate_pipe_open(conn, req); - END_PROFILE(SMBntcreateX); - return; + goto out; } reply_doserror(req, ERRDOS, ERRnoaccess); - END_PROFILE(SMBntcreateX); - return; + goto out; } oplock_request = (flags & REQUEST_OPLOCK) ? EXCLUSIVE_OPLOCK : 0; @@ -510,12 +475,30 @@ void reply_ntcreate_and_X(struct smb_request *req) ? BATCH_OPLOCK : 0; } + status = filename_convert(ctx, + conn, + req->flags2 & FLAGS2_DFS_PATHNAMES, + fname, + 0, + NULL, + &smb_fname); + + if (!NT_STATUS_IS_OK(status)) { + if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { + reply_botherror(req, + NT_STATUS_PATH_NOT_COVERED, + ERRSRV, ERRbadpath); + goto out; + } + reply_nterror(req, status); + goto out; + } + status = SMB_VFS_CREATE_FILE( conn, /* conn */ req, /* req */ root_dir_fid, /* root_dir_fid */ - fname, /* fname */ - CFF_DOS_PATH, /* create_file_flags */ + smb_fname, /* fname */ access_mask, /* access_mask */ share_access, /* share_access */ create_disposition, /* create_disposition*/ @@ -526,14 +509,12 @@ void reply_ntcreate_and_X(struct smb_request *req) NULL, /* sd */ NULL, /* ea_list */ &fsp, /* result */ - &info, /* pinfo */ - &sbuf); /* psbuf */ + &info); /* pinfo */ if (!NT_STATUS_IS_OK(status)) { if (open_was_deferred(req->mid)) { /* We have re-scheduled this call, no error. */ - END_PROFILE(SMBntcreateX); - return; + goto out; } if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) { reply_botherror(req, status, ERRDOS, ERRfilexists); @@ -541,10 +522,13 @@ void reply_ntcreate_and_X(struct smb_request *req) else { reply_nterror(req, status); } - END_PROFILE(SMBntcreateX); - return; + goto out; } + /* Ensure we're pointing at the correct stat struct. */ + TALLOC_FREE(smb_fname); + smb_fname = fsp->fsp_name; + /* * If the caller set the extended oplock request bit * and we granted one (by whatever means) - set the @@ -570,8 +554,8 @@ void reply_ntcreate_and_X(struct smb_request *req) oplock_granted = NO_OPLOCK_RETURN; } - file_len = sbuf.st_size; - fattr = dos_mode(conn,fsp->fsp_name,&sbuf); + file_len = smb_fname->st.st_ex_size; + fattr = dos_mode(conn, smb_fname); if (fattr == 0) { fattr = FILE_ATTRIBUTE_NORMAL; } @@ -603,34 +587,61 @@ void reply_ntcreate_and_X(struct smb_request *req) } p += 4; + /* Deal with other possible opens having a modified + write time. JRA. */ + ZERO_STRUCT(write_time_ts); + get_file_infos(fsp->file_id, NULL, &write_time_ts); + if (!null_timespec(write_time_ts)) { + update_stat_ex_mtime(&smb_fname->st, write_time_ts); + } + /* Create time. */ - c_timespec = get_create_timespec( - &sbuf,lp_fake_dir_create_times(SNUM(conn))); - a_timespec = get_atimespec(&sbuf); - m_timespec = get_mtimespec(&sbuf); + create_timespec = get_create_timespec(conn, fsp, smb_fname); + a_timespec = smb_fname->st.st_ex_atime; + m_timespec = smb_fname->st.st_ex_mtime; + c_timespec = get_change_timespec(conn, fsp, smb_fname); if (lp_dos_filetime_resolution(SNUM(conn))) { - dos_filetime_timespec(&c_timespec); + dos_filetime_timespec(&create_timespec); dos_filetime_timespec(&a_timespec); dos_filetime_timespec(&m_timespec); + dos_filetime_timespec(&c_timespec); } - put_long_date_timespec(p, c_timespec); /* create time. */ + put_long_date_timespec(conn->ts_res, p, create_timespec); /* create time. */ p += 8; - put_long_date_timespec(p, a_timespec); /* access time */ + put_long_date_timespec(conn->ts_res, p, a_timespec); /* access time */ p += 8; - put_long_date_timespec(p, m_timespec); /* write time */ + put_long_date_timespec(conn->ts_res, p, m_timespec); /* write time */ p += 8; - put_long_date_timespec(p, m_timespec); /* change time */ + put_long_date_timespec(conn->ts_res, p, c_timespec); /* change time */ p += 8; SIVAL(p,0,fattr); /* File Attributes. */ p += 4; - SOFF_T(p, 0, SMB_VFS_GET_ALLOC_SIZE(conn,fsp,&sbuf)); + SOFF_T(p, 0, SMB_VFS_GET_ALLOC_SIZE(conn,fsp,&smb_fname->st)); p += 8; SOFF_T(p,0,file_len); p += 8; if (flags & EXTENDED_RESPONSE_REQUIRED) { - SSVAL(p,2,0x7); + uint16_t file_status = (NO_EAS|NO_SUBSTREAMS|NO_REPARSETAG); + size_t num_names = 0; + unsigned int num_streams; + struct stream_struct *streams = NULL; + + /* Do we have any EA's ? */ + status = get_ea_names_from_file(ctx, conn, fsp, + smb_fname->base_name, NULL, &num_names); + if (NT_STATUS_IS_OK(status) && num_names) { + file_status &= ~NO_EAS; + } + status = SMB_VFS_STREAMINFO(conn, NULL, smb_fname->base_name, ctx, + &num_streams, &streams); + /* There is always one stream, ::$DATA. */ + if (NT_STATUS_IS_OK(status) && num_streams > 1) { + file_status &= ~NO_SUBSTREAMS; + } + TALLOC_FREE(streams); + SSVAL(p,2,file_status); } p += 4; SCVAL(p,0,fsp->is_directory ? 1 : 0); @@ -638,8 +649,8 @@ void reply_ntcreate_and_X(struct smb_request *req) if (flags & EXTENDED_RESPONSE_REQUIRED) { uint32 perms = 0; p += 25; - if (fsp->is_directory - || can_write_to_file(conn, fsp->fsp_name, &sbuf)) { + if (fsp->is_directory || + can_write_to_file(conn, smb_fname)) { perms = FILE_GENERIC_ALL; } else { perms = FILE_GENERIC_READ|FILE_EXECUTE; @@ -648,9 +659,10 @@ void reply_ntcreate_and_X(struct smb_request *req) } DEBUG(5,("reply_ntcreate_and_X: fnum = %d, open name = %s\n", - fsp->fnum, fsp->fsp_name)); + fsp->fnum, smb_fname_str_dbg(smb_fname))); chain_reply(req); + out: END_PROFILE(SMBntcreateX); return; } @@ -783,7 +795,7 @@ static NTSTATUS set_sd(files_struct *fsp, uint8 *data, uint32 sd_len, security_acl_map_generic(psd->sacl, &file_generic_mapping); if (DEBUGLEVEL >= 10) { - DEBUG(10,("set_sd for file %s\n", fsp->fsp_name )); + DEBUG(10,("set_sd for file %s\n", fsp_str_dbg(fsp))); NDR_PRINT_DEBUG(security_descriptor, psd); } @@ -798,7 +810,7 @@ static NTSTATUS set_sd(files_struct *fsp, uint8 *data, uint32 sd_len, Read a list of EA names and data from an incoming data buffer. Create an ea_list with them. ****************************************************************************/ -static struct ea_list *read_nttrans_ea_list(TALLOC_CTX *ctx, const char *pdata, size_t data_size) +struct ea_list *read_nttrans_ea_list(TALLOC_CTX *ctx, const char *pdata, size_t data_size) { struct ea_list *ea_list_head = NULL; size_t offset = 0; @@ -836,13 +848,13 @@ static void call_nt_transact_create(connection_struct *conn, char **ppdata, uint32 data_count, uint32 max_data_count) { + struct smb_filename *smb_fname = NULL; char *fname = NULL; char *params = *ppparams; char *data = *ppdata; /* Breakout the oplock request bits so we can set the reply bits separately. */ uint32 fattr=0; SMB_OFF_T file_len = 0; - SMB_STRUCT_STAT sbuf; int info = 0; files_struct *fsp = NULL; char *p = NULL; @@ -856,9 +868,11 @@ static void call_nt_transact_create(connection_struct *conn, struct security_descriptor *sd = NULL; uint32 ea_len; uint16 root_dir_fid; + struct timespec create_timespec; struct timespec c_timespec; struct timespec a_timespec; struct timespec m_timespec; + struct timespec write_time_ts; struct ea_list *ea_list = NULL; NTSTATUS status; size_t param_len; @@ -867,8 +881,6 @@ static void call_nt_transact_create(connection_struct *conn, uint8_t oplock_granted; TALLOC_CTX *ctx = talloc_tos(); - SET_STAT_INVALID(sbuf); - DEBUG(5,("call_nt_transact_create\n")); /* @@ -882,10 +894,10 @@ static void call_nt_transact_create(connection_struct *conn, ppsetup, setup_count, ppparams, parameter_count, ppdata, data_count); - return; + goto out; } reply_doserror(req, ERRDOS, ERRnoaccess); - return; + goto out; } /* @@ -895,7 +907,7 @@ static void call_nt_transact_create(connection_struct *conn, if(parameter_count < 54) { DEBUG(0,("call_nt_transact_create - insufficient parameters (%u)\n", (unsigned int)parameter_count)); reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - return; + goto out; } flags = IVAL(params,0); @@ -926,7 +938,7 @@ static void call_nt_transact_create(connection_struct *conn, "%u, data_count = %u\n", (unsigned int)ea_len, (unsigned int)sd_len, (unsigned int)data_count)); reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - return; + goto out; } if (sd_len) { @@ -940,7 +952,7 @@ static void call_nt_transact_create(connection_struct *conn, "unmarshall_sec_desc failed: %s\n", nt_errstr(status))); reply_nterror(req, status); - return; + goto out; } } @@ -950,7 +962,7 @@ static void call_nt_transact_create(connection_struct *conn, "EA's not supported.\n", (unsigned int)ea_len)); reply_nterror(req, NT_STATUS_EAS_NOT_SUPPORTED); - return; + goto out; } if (ea_len < 10) { @@ -958,7 +970,7 @@ static void call_nt_transact_create(connection_struct *conn, "too small (should be more than 10)\n", (unsigned int)ea_len )); reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - return; + goto out; } /* We have already checked that ea_len <= data_count here. */ @@ -966,7 +978,7 @@ static void call_nt_transact_create(connection_struct *conn, ea_len); if (ea_list == NULL) { reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - return; + goto out; } } @@ -975,7 +987,26 @@ static void call_nt_transact_create(connection_struct *conn, STR_TERMINATE, &status); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); - return; + goto out; + } + + status = filename_convert(ctx, + conn, + req->flags2 & FLAGS2_DFS_PATHNAMES, + fname, + 0, + NULL, + &smb_fname); + + if (!NT_STATUS_IS_OK(status)) { + if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { + reply_botherror(req, + NT_STATUS_PATH_NOT_COVERED, + ERRSRV, ERRbadpath); + goto out; + } + reply_nterror(req, status); + goto out; } oplock_request = (flags & REQUEST_OPLOCK) ? EXCLUSIVE_OPLOCK : 0; @@ -988,8 +1019,7 @@ static void call_nt_transact_create(connection_struct *conn, conn, /* conn */ req, /* req */ root_dir_fid, /* root_dir_fid */ - fname, /* fname */ - CFF_DOS_PATH, /* create_file_flags */ + smb_fname, /* fname */ access_mask, /* access_mask */ share_access, /* share_access */ create_disposition, /* create_disposition*/ @@ -1000,8 +1030,7 @@ static void call_nt_transact_create(connection_struct *conn, sd, /* sd */ ea_list, /* ea_list */ &fsp, /* result */ - &info, /* pinfo */ - &sbuf); /* psbuf */ + &info); /* pinfo */ if(!NT_STATUS_IS_OK(status)) { if (open_was_deferred(req->mid)) { @@ -1009,9 +1038,13 @@ static void call_nt_transact_create(connection_struct *conn, return; } reply_openerror(req, status); - return; + goto out; } + /* Ensure we're pointing at the correct stat struct. */ + TALLOC_FREE(smb_fname); + smb_fname = fsp->fsp_name; + /* * If the caller set the extended oplock request bit * and we granted one (by whatever means) - set the @@ -1037,8 +1070,8 @@ static void call_nt_transact_create(connection_struct *conn, oplock_granted = NO_OPLOCK_RETURN; } - file_len = sbuf.st_size; - fattr = dos_mode(conn,fsp->fsp_name,&sbuf); + file_len = smb_fname->st.st_ex_size; + fattr = dos_mode(conn, smb_fname); if (fattr == 0) { fattr = FILE_ATTRIBUTE_NORMAL; } @@ -1053,7 +1086,7 @@ static void call_nt_transact_create(connection_struct *conn, params = nttrans_realloc(ppparams, param_len); if(params == NULL) { reply_doserror(req, ERRDOS, ERRnomem); - return; + goto out; } p = params; @@ -1070,29 +1103,38 @@ static void call_nt_transact_create(connection_struct *conn, } p += 8; + /* Deal with other possible opens having a modified + write time. JRA. */ + ZERO_STRUCT(write_time_ts); + get_file_infos(fsp->file_id, NULL, &write_time_ts); + if (!null_timespec(write_time_ts)) { + update_stat_ex_mtime(&smb_fname->st, write_time_ts); + } + /* Create time. */ - c_timespec = get_create_timespec( - &sbuf,lp_fake_dir_create_times(SNUM(conn))); - a_timespec = get_atimespec(&sbuf); - m_timespec = get_mtimespec(&sbuf); + create_timespec = get_create_timespec(conn, fsp, smb_fname); + a_timespec = smb_fname->st.st_ex_atime; + m_timespec = smb_fname->st.st_ex_mtime; + c_timespec = get_change_timespec(conn, fsp, smb_fname); if (lp_dos_filetime_resolution(SNUM(conn))) { - dos_filetime_timespec(&c_timespec); + dos_filetime_timespec(&create_timespec); dos_filetime_timespec(&a_timespec); dos_filetime_timespec(&m_timespec); + dos_filetime_timespec(&c_timespec); } - put_long_date_timespec(p, c_timespec); /* create time. */ + put_long_date_timespec(conn->ts_res, p, create_timespec); /* create time. */ p += 8; - put_long_date_timespec(p, a_timespec); /* access time */ + put_long_date_timespec(conn->ts_res, p, a_timespec); /* access time */ p += 8; - put_long_date_timespec(p, m_timespec); /* write time */ + put_long_date_timespec(conn->ts_res, p, m_timespec); /* write time */ p += 8; - put_long_date_timespec(p, m_timespec); /* change time */ + put_long_date_timespec(conn->ts_res, p, c_timespec); /* change time */ p += 8; SIVAL(p,0,fattr); /* File Attributes. */ p += 4; - SOFF_T(p, 0, SMB_VFS_GET_ALLOC_SIZE(conn,fsp,&sbuf)); + SOFF_T(p, 0, SMB_VFS_GET_ALLOC_SIZE(conn, fsp, &smb_fname->st)); p += 8; SOFF_T(p,0,file_len); p += 8; @@ -1105,8 +1147,8 @@ static void call_nt_transact_create(connection_struct *conn, if (flags & EXTENDED_RESPONSE_REQUIRED) { uint32 perms = 0; p += 25; - if (fsp->is_directory - || can_write_to_file(conn, fsp->fsp_name, &sbuf)) { + if (fsp->is_directory || + can_write_to_file(conn, smb_fname)) { perms = FILE_GENERIC_ALL; } else { perms = FILE_GENERIC_READ|FILE_EXECUTE; @@ -1114,11 +1156,12 @@ static void call_nt_transact_create(connection_struct *conn, SIVAL(p,0,perms); } - DEBUG(5,("call_nt_transact_create: open name = %s\n", fsp->fsp_name)); + DEBUG(5,("call_nt_transact_create: open name = %s\n", + smb_fname_str_dbg(smb_fname))); /* Send the required number of replies */ send_nt_replies(conn, req, NT_STATUS_OK, params, param_len, *ppdata, 0); - + out: return; } @@ -1151,14 +1194,10 @@ void reply_ntcancel(struct smb_request *req) static NTSTATUS copy_internals(TALLOC_CTX *ctx, connection_struct *conn, struct smb_request *req, - const char *oldname_in, - const char *newname_in, + struct smb_filename *smb_fname_src, + struct smb_filename *smb_fname_dst, uint32 attrs) { - struct smb_filename *smb_fname = NULL; - struct smb_filename *smb_fname_new = NULL; - char *oldname = NULL; - char *newname = NULL; files_struct *fsp1,*fsp2; uint32 fattr; int info; @@ -1171,75 +1210,40 @@ static NTSTATUS copy_internals(TALLOC_CTX *ctx, goto out; } - status = unix_convert(ctx, conn, oldname_in, &smb_fname, 0); - if (!NT_STATUS_IS_OK(status)) { - goto out; - } - - status = get_full_smb_filename(ctx, smb_fname, &oldname); - if (!NT_STATUS_IS_OK(status)) { - goto out; - } - - status = check_name(conn, oldname); - if (!NT_STATUS_IS_OK(status)) { - goto out; - } - /* Source must already exist. */ - if (!VALID_STAT(smb_fname->st)) { + if (!VALID_STAT(smb_fname_src->st)) { status = NT_STATUS_OBJECT_NAME_NOT_FOUND; goto out; } + /* Ensure attributes match. */ - fattr = dos_mode(conn, oldname, &smb_fname->st); + fattr = dos_mode(conn, smb_fname_src); if ((fattr & ~attrs) & (aHIDDEN | aSYSTEM)) { status = NT_STATUS_NO_SUCH_FILE; goto out; } - status = unix_convert(ctx, conn, newname_in, &smb_fname_new, 0); - if (!NT_STATUS_IS_OK(status)) { - goto out; - } - - status = get_full_smb_filename(ctx, smb_fname_new, &newname); - if (!NT_STATUS_IS_OK(status)) { - goto out; - } - - status = check_name(conn, newname); - if (!NT_STATUS_IS_OK(status)) { - goto out; - } - - /* Disallow if newname already exists. */ - if (VALID_STAT(smb_fname_new->st)) { + /* Disallow if dst file already exists. */ + if (VALID_STAT(smb_fname_dst->st)) { status = NT_STATUS_OBJECT_NAME_COLLISION; goto out; } /* No links from a directory. */ - if (S_ISDIR(smb_fname->st.st_mode)) { + if (S_ISDIR(smb_fname_src->st.st_ex_mode)) { status = NT_STATUS_FILE_IS_A_DIRECTORY; goto out; } - /* Ensure this is within the share. */ - status = check_reduced_name(conn, oldname); - if (!NT_STATUS_IS_OK(status)) { - goto out; - } - DEBUG(10,("copy_internals: doing file copy %s to %s\n", - oldname, newname)); + smb_fname_str_dbg(smb_fname_src), + smb_fname_str_dbg(smb_fname_dst))); status = SMB_VFS_CREATE_FILE( conn, /* conn */ req, /* req */ 0, /* root_dir_fid */ - oldname, /* fname */ - 0, /* create_file_flags */ + smb_fname_src, /* fname */ FILE_READ_DATA, /* access_mask */ (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */ FILE_SHARE_DELETE), @@ -1251,8 +1255,7 @@ static NTSTATUS copy_internals(TALLOC_CTX *ctx, NULL, /* sd */ NULL, /* ea_list */ &fsp1, /* result */ - &info, /* pinfo */ - &smb_fname->st); /* psbuf */ + &info); /* pinfo */ if (!NT_STATUS_IS_OK(status)) { goto out; @@ -1262,8 +1265,7 @@ static NTSTATUS copy_internals(TALLOC_CTX *ctx, conn, /* conn */ req, /* req */ 0, /* root_dir_fid */ - newname, /* fname */ - 0, /* create_file_flags */ + smb_fname_dst, /* fname */ FILE_WRITE_DATA, /* access_mask */ (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */ FILE_SHARE_DELETE), @@ -1275,16 +1277,15 @@ static NTSTATUS copy_internals(TALLOC_CTX *ctx, NULL, /* sd */ NULL, /* ea_list */ &fsp2, /* result */ - &info, /* pinfo */ - &smb_fname_new->st); /* psbuf */ + &info); /* pinfo */ if (!NT_STATUS_IS_OK(status)) { close_file(NULL, fsp1, ERROR_CLOSE); goto out; } - if (smb_fname->st.st_size) { - ret = vfs_transfer_file(fsp1, fsp2, smb_fname->st.st_size); + if (smb_fname_src->st.st_ex_size) { + ret = vfs_transfer_file(fsp1, fsp2, smb_fname_src->st.st_ex_size); } /* @@ -1296,32 +1297,32 @@ static NTSTATUS copy_internals(TALLOC_CTX *ctx, close_file(NULL, fsp1, NORMAL_CLOSE); /* Ensure the modtime is set correctly on the destination file. */ - set_close_write_time(fsp2, get_mtimespec(&smb_fname->st)); + set_close_write_time(fsp2, smb_fname_src->st.st_ex_mtime); status = close_file(NULL, fsp2, NORMAL_CLOSE); /* Grrr. We have to do this as open_file_ntcreate adds aARCH when it creates the file. This isn't the correct thing to do in the copy case. JRA */ - if (!parent_dirname(talloc_tos(), newname, &parent, NULL)) { + if (!parent_dirname(talloc_tos(), smb_fname_dst->base_name, &parent, + NULL)) { status = NT_STATUS_NO_MEMORY; goto out; } - file_set_dosmode(conn, newname, fattr, &smb_fname_new->st, parent, - false); + file_set_dosmode(conn, smb_fname_dst, fattr, parent, false); TALLOC_FREE(parent); - if (ret < (SMB_OFF_T)smb_fname->st.st_size) { + if (ret < (SMB_OFF_T)smb_fname_src->st.st_ex_size) { status = NT_STATUS_DISK_FULL; goto out; } out: - TALLOC_FREE(smb_fname); - TALLOC_FREE(smb_fname_new); if (!NT_STATUS_IS_OK(status)) { DEBUG(3,("copy_internals: Error %s copy file %s to %s\n", - nt_errstr(status), oldname, newname)); + nt_errstr(status), smb_fname_str_dbg(smb_fname_src), + smb_fname_str_dbg(smb_fname_dst))); } + return status; } @@ -1332,6 +1333,8 @@ static NTSTATUS copy_internals(TALLOC_CTX *ctx, void reply_ntrename(struct smb_request *req) { connection_struct *conn = req->conn; + struct smb_filename *smb_fname_old = NULL; + struct smb_filename *smb_fname_new = NULL; char *oldname = NULL; char *newname = NULL; const char *p; @@ -1339,6 +1342,8 @@ void reply_ntrename(struct smb_request *req) bool src_has_wcard = False; bool dest_has_wcard = False; uint32 attrs; + uint32_t ucf_flags_src = 0; + uint32_t ucf_flags_dst = 0; uint16 rename_type; TALLOC_CTX *ctx = talloc_tos(); @@ -1346,8 +1351,7 @@ void reply_ntrename(struct smb_request *req) if (req->wct < 4) { reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - END_PROFILE(SMBntrename); - return; + goto out; } attrs = SVAL(req->vwv+0, 0); @@ -1358,14 +1362,12 @@ void reply_ntrename(struct smb_request *req) &status, &src_has_wcard); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); - END_PROFILE(SMBntrename); - return; + goto out; } if (ms_has_wild(oldname)) { reply_nterror(req, NT_STATUS_OBJECT_PATH_SYNTAX_BAD); - END_PROFILE(SMBntrename); - return; + goto out; } p++; @@ -1373,66 +1375,81 @@ void reply_ntrename(struct smb_request *req) &status, &dest_has_wcard); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); - END_PROFILE(SMBntrename); - return; + goto out; } - status = resolve_dfspath(ctx, conn, - req->flags2 & FLAGS2_DFS_PATHNAMES, - oldname, - &oldname); + /* The newname must begin with a ':' if the oldname contains a ':'. */ + if (strchr_m(oldname, ':') && (newname[0] != ':')) { + reply_nterror(req, NT_STATUS_INVALID_PARAMETER); + goto out; + } + + /* + * If this is a rename operation, allow wildcards and save the + * destination's last component. + */ + if (rename_type == RENAME_FLAG_RENAME) { + ucf_flags_src = UCF_COND_ALLOW_WCARD_LCOMP; + ucf_flags_dst = UCF_COND_ALLOW_WCARD_LCOMP | UCF_SAVE_LCOMP; + } + + /* rename_internals() calls unix_convert(), so don't call it here. */ + status = filename_convert(ctx, conn, + req->flags2 & FLAGS2_DFS_PATHNAMES, + oldname, + ucf_flags_src, + NULL, + &smb_fname_old); if (!NT_STATUS_IS_OK(status)) { - if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { - reply_botherror(req, NT_STATUS_PATH_NOT_COVERED, + if (NT_STATUS_EQUAL(status, + NT_STATUS_PATH_NOT_COVERED)) { + reply_botherror(req, + NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath); - END_PROFILE(SMBntrename); - return; + goto out; } reply_nterror(req, status); - END_PROFILE(SMBntrename); - return; + goto out; } - status = resolve_dfspath(ctx, conn, - req->flags2 & FLAGS2_DFS_PATHNAMES, - newname, - &newname); + status = filename_convert(ctx, conn, + req->flags2 & FLAGS2_DFS_PATHNAMES, + newname, + ucf_flags_dst, + &dest_has_wcard, + &smb_fname_new); if (!NT_STATUS_IS_OK(status)) { - if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { - reply_botherror(req, NT_STATUS_PATH_NOT_COVERED, + if (NT_STATUS_EQUAL(status, + NT_STATUS_PATH_NOT_COVERED)) { + reply_botherror(req, + NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath); - END_PROFILE(SMBntrename); - return; + goto out; } reply_nterror(req, status); - END_PROFILE(SMBntrename); - return; - } - - /* The new name must begin with a ':' if the old name is a stream. */ - if (is_ntfs_stream_name(oldname) && (newname[0] != ':')) { - reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - END_PROFILE(SMBntrename); - return; + goto out; } - DEBUG(3,("reply_ntrename : %s -> %s\n",oldname,newname)); + DEBUG(3,("reply_ntrename: %s -> %s\n", + smb_fname_str_dbg(smb_fname_old), + smb_fname_str_dbg(smb_fname_new))); switch(rename_type) { case RENAME_FLAG_RENAME: - status = rename_internals(ctx, conn, req, oldname, - newname, attrs, False, src_has_wcard, - dest_has_wcard, DELETE_ACCESS); + status = rename_internals(ctx, conn, req, + smb_fname_old, smb_fname_new, + attrs, False, src_has_wcard, + dest_has_wcard, + DELETE_ACCESS); break; case RENAME_FLAG_HARD_LINK: if (src_has_wcard || dest_has_wcard) { /* No wildcards. */ status = NT_STATUS_OBJECT_PATH_SYNTAX_BAD; } else { - status = hardlink_internals(ctx, - conn, - oldname, - newname); + status = hardlink_internals(ctx, conn, + smb_fname_old, + smb_fname_new); } break; case RENAME_FLAG_COPY: @@ -1440,8 +1457,10 @@ void reply_ntrename(struct smb_request *req) /* No wildcards. */ status = NT_STATUS_OBJECT_PATH_SYNTAX_BAD; } else { - status = copy_internals(ctx, conn, req, oldname, - newname, attrs); + status = copy_internals(ctx, conn, req, + smb_fname_old, + smb_fname_new, + attrs); } break; case RENAME_FLAG_MOVE_CLUSTER_INFORMATION: @@ -1455,17 +1474,15 @@ void reply_ntrename(struct smb_request *req) if (!NT_STATUS_IS_OK(status)) { if (open_was_deferred(req->mid)) { /* We have re-scheduled this call. */ - END_PROFILE(SMBntrename); - return; + goto out; } reply_nterror(req, status); - END_PROFILE(SMBntrename); - return; + goto out; } reply_outbuf(req, 0, 0); - + out: END_PROFILE(SMBntrename); return; } @@ -1475,6 +1492,13 @@ void reply_ntrename(struct smb_request *req) don't allow a directory to be opened. ****************************************************************************/ +static void smbd_smb1_notify_reply(struct smb_request *req, + NTSTATUS error_code, + uint8_t *buf, size_t len) +{ + send_nt_replies(req->conn, req, error_code, (char *)buf, len, NULL, 0); +} + static void call_nt_transact_notify_change(connection_struct *conn, struct smb_request *req, uint16 **ppsetup, @@ -1517,7 +1541,7 @@ static void call_nt_transact_notify_change(connection_struct *conn, DEBUG(3,("call_nt_transact_notify_change: notify change " "called on %s, filter = %s, recursive = %d\n", - fsp->fsp_name, filter_string, recursive)); + fsp_str_dbg(fsp), filter_string, recursive)); TALLOC_FREE(filter_string); } @@ -1550,8 +1574,11 @@ static void call_nt_transact_notify_change(connection_struct *conn, * here. */ - change_notify_reply(fsp->conn, req, max_param_count, - fsp->notify); + change_notify_reply(fsp->conn, req, + NT_STATUS_OK, + max_param_count, + fsp->notify, + smbd_smb1_notify_reply); /* * change_notify_reply() above has independently sent its @@ -1567,7 +1594,8 @@ static void call_nt_transact_notify_change(connection_struct *conn, status = change_notify_add_request(req, max_param_count, filter, - recursive, fsp); + recursive, fsp, + smbd_smb1_notify_reply); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); } @@ -1616,7 +1644,7 @@ static void call_nt_transact_rename(connection_struct *conn, send_nt_replies(conn, req, NT_STATUS_OK, NULL, 0, NULL, 0); DEBUG(3,("nt transact rename from = %s, to = %s ignored!\n", - fsp->fsp_name, new_name)); + fsp_str_dbg(fsp), new_name)); return; } @@ -1674,8 +1702,9 @@ static void call_nt_transact_query_security_desc(connection_struct *conn, security_info_wanted = IVAL(params,4); - DEBUG(3,("call_nt_transact_query_security_desc: file = %s, info_wanted = 0x%x\n", fsp->fsp_name, - (unsigned int)security_info_wanted )); + DEBUG(3,("call_nt_transact_query_security_desc: file = %s, " + "info_wanted = 0x%x\n", fsp_str_dbg(fsp), + (unsigned int)security_info_wanted)); params = nttrans_realloc(ppparams, 4); if(params == NULL) { @@ -1712,7 +1741,8 @@ static void call_nt_transact_query_security_desc(connection_struct *conn, DEBUG(3,("call_nt_transact_query_security_desc: sd_size = %lu.\n",(unsigned long)sd_size)); if (DEBUGLEVEL >= 10) { - DEBUG(10,("call_nt_transact_query_security_desc for file %s\n", fsp->fsp_name)); + DEBUG(10,("call_nt_transact_query_security_desc for file %s\n", + fsp_str_dbg(fsp))); NDR_PRINT_DEBUG(security_descriptor, psd); } @@ -1786,8 +1816,8 @@ static void call_nt_transact_set_security_desc(connection_struct *conn, security_info_sent = IVAL(params,4); - DEBUG(3,("call_nt_transact_set_security_desc: file = %s, sent 0x%x\n", fsp->fsp_name, - (unsigned int)security_info_sent )); + DEBUG(3,("call_nt_transact_set_security_desc: file = %s, sent 0x%x\n", + fsp_str_dbg(fsp), (unsigned int)security_info_sent)); if (data_count == 0) { reply_doserror(req, ERRDOS, ERRnoaccess); @@ -2006,12 +2036,12 @@ static void call_nt_transact_ioctl(connection_struct *conn, } /* needed_data_count 4 bytes */ - SIVAL(pdata,8,labels_data_count); + SIVAL(pdata, 8, labels_data_count+4); cur_pdata+=12; DEBUG(10,("FSCTL_GET_SHADOW_COPY_DATA: %u volumes for path[%s].\n", - shadow_data->num_volumes,fsp->fsp_name)); + shadow_data->num_volumes, fsp_str_dbg(fsp))); if (labels && shadow_data->labels) { for (i=0;inum_volumes;i++) { srvstr_push(pdata, req->flags2,