X-Git-Url: http://git.samba.org/samba.git/?p=tprouty%2Fsamba.git;a=blobdiff_plain;f=source%2Fsmbd%2Fnttrans.c;h=0b48fa2c4d522104de041149bb013ccec8ead3b7;hp=bbbde066194c09ccae46b8c50bc6d35ace031fb8;hb=ef6697435efba2afe15498caeb5daae7aea10604;hpb=f35a266b3cbb3e5fa6a86be60f34fe340a3ca71f diff --git a/source/smbd/nttrans.c b/source/smbd/nttrans.c index bbbde06619..0b48fa2c4d 100644 --- a/source/smbd/nttrans.c +++ b/source/smbd/nttrans.c @@ -22,7 +22,6 @@ extern int max_send; extern enum protocol_types Protocol; -extern int smb_read_error; extern struct current_user current_user; static const char *known_nt_pipes[] = { @@ -67,7 +66,8 @@ static char *nttrans_realloc(char **ptr, size_t size) HACK ! Always assumes smb_setup field is zero. ****************************************************************************/ -void send_nt_replies(struct smb_request *req, NTSTATUS nt_error, +void send_nt_replies(connection_struct *conn, + struct smb_request *req, NTSTATUS nt_error, char *params, int paramsize, char *pdata, int datasize) { @@ -243,8 +243,10 @@ void send_nt_replies(struct smb_request *req, NTSTATUS nt_error, /* Send the packet */ show_msg((char *)req->outbuf); - if (!send_smb(smbd_server_fd(),(char *)req->outbuf)) { - exit_server_cleanly("send_nt_replies: send_smb failed."); + if (!srv_send_smb(smbd_server_fd(), + (char *)req->outbuf, + IS_CONN_ENCRYPTED(conn))) { + exit_server_cleanly("send_nt_replies: srv_send_smb failed."); } TALLOC_FREE(req->outbuf); @@ -269,6 +271,9 @@ void send_nt_replies(struct smb_request *req, NTSTATUS nt_error, /**************************************************************************** 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. ****************************************************************************/ bool is_ntfs_stream_name(const char *fname) @@ -279,52 +284,6 @@ bool is_ntfs_stream_name(const char *fname) return (strchr_m(fname, ':') != NULL) ? True : False; } -struct case_semantics_state { - connection_struct *conn; - bool case_sensitive; - bool case_preserve; - bool short_case_preserve; -}; - -/**************************************************************************** - Restore case semantics. -****************************************************************************/ -static int restore_case_semantics(struct case_semantics_state *state) -{ - state->conn->case_sensitive = state->case_sensitive; - state->conn->case_preserve = state->case_preserve; - state->conn->short_case_preserve = state->short_case_preserve; - return 0; -} - -/**************************************************************************** - Save case semantics. -****************************************************************************/ -static struct case_semantics_state *set_posix_case_semantics(TALLOC_CTX *mem_ctx, - connection_struct *conn) -{ - struct case_semantics_state *result; - - if (!(result = talloc(mem_ctx, struct case_semantics_state))) { - DEBUG(0, ("talloc failed\n")); - return NULL; - } - - result->conn = conn; - result->case_sensitive = conn->case_sensitive; - result->case_preserve = conn->case_preserve; - result->short_case_preserve = conn->short_case_preserve; - - /* Set to POSIX. */ - conn->case_sensitive = True; - conn->case_preserve = True; - conn->short_case_preserve = True; - - talloc_set_destructor(result, restore_case_semantics); - - return result; -} - /**************************************************************************** Reply to an NT create and X call on a pipe ****************************************************************************/ @@ -453,48 +412,13 @@ static void do_ntcreate_pipe_open(connection_struct *conn, chain_reply(req); } -/**************************************************************************** - Reply to an NT create and X call for a quota file. -****************************************************************************/ - -static void reply_ntcreate_and_X_quota(connection_struct *conn, - struct smb_request *req, - enum FAKE_FILE_TYPE fake_file_type, - const char *fname) -{ - char *p; - uint32 desired_access = IVAL(req->inbuf,smb_ntcreate_DesiredAccess); - files_struct *fsp; - NTSTATUS status; - - status = open_fake_file(conn, fake_file_type, fname, desired_access, - &fsp); - - if (!NT_STATUS_IS_OK(status)) { - reply_nterror(req, status); - return; - } - - reply_outbuf(req, 34, 0); - - p = (char *)req->outbuf + smb_vwv2; - - /* SCVAL(p,0,NO_OPLOCK_RETURN); */ - p++; - SSVAL(p,0,fsp->fnum); - - DEBUG(5,("reply_ntcreate_and_X_quota: fnum = %d, open name = %s\n", fsp->fnum, fsp->fsp_name)); - - chain_reply(req); -} - /**************************************************************************** Reply to an NT create and X call. ****************************************************************************/ -void reply_ntcreate_and_X(connection_struct *conn, - struct smb_request *req) +void reply_ntcreate_and_X(struct smb_request *req) { + connection_struct *conn = req->conn; char *fname = NULL; uint32 flags; uint32 access_mask; @@ -506,7 +430,6 @@ void reply_ntcreate_and_X(connection_struct *conn, SMB_BIG_UINT allocation_size; /* Breakout the oplock request bits so we can set the reply bits separately. */ - int oplock_request = 0; uint32 fattr=0; SMB_OFF_T file_len = 0; SMB_STRUCT_STAT sbuf; @@ -516,9 +439,9 @@ void reply_ntcreate_and_X(connection_struct *conn, struct timespec c_timespec; struct timespec a_timespec; struct timespec m_timespec; - bool extended_oplock_granted = False; NTSTATUS status; - struct case_semantics_state *case_state = NULL; + int oplock_request; + uint8_t oplock_granted = NO_OPLOCK_RETURN; TALLOC_CTX *ctx = talloc_tos(); START_PROFILE(SMBntcreateX); @@ -536,22 +459,41 @@ void reply_ntcreate_and_X(connection_struct *conn, create_options = IVAL(req->inbuf,smb_ntcreate_CreateOptions); root_dir_fid = (uint16)IVAL(req->inbuf,smb_ntcreate_RootDirectoryFid); - allocation_size = (SMB_BIG_UINT)IVAL(req->inbuf,smb_ntcreate_AllocationSize); + allocation_size = (SMB_BIG_UINT)IVAL(req->inbuf, + smb_ntcreate_AllocationSize); #ifdef LARGE_SMB_OFF_T - allocation_size |= (((SMB_BIG_UINT)IVAL(req->inbuf,smb_ntcreate_AllocationSize + 4)) << 32); + allocation_size |= (((SMB_BIG_UINT)IVAL( + req->inbuf, + smb_ntcreate_AllocationSize + 4)) << 32); #endif + srvstr_get_path(ctx, (char *)req->inbuf, req->flags2, &fname, + smb_buf(req->inbuf), 0, STR_TERMINATE, &status); + + if (!NT_STATUS_IS_OK(status)) { + reply_nterror(req, status); + END_PROFILE(SMBntcreateX); + return; + } + DEBUG(10,("reply_ntcreate_and_X: flags = 0x%x, access_mask = 0x%x " "file_attributes = 0x%x, share_access = 0x%x, " "create_disposition = 0x%x create_options = 0x%x " - "root_dir_fid = 0x%x\n", + "root_dir_fid = 0x%x, fname = %s\n", (unsigned int)flags, (unsigned int)access_mask, (unsigned int)file_attributes, (unsigned int)share_access, (unsigned int)create_disposition, (unsigned int)create_options, - (unsigned int)root_dir_fid )); + (unsigned int)root_dir_fid, + fname)); + + /* + * we need to remove ignored bits when they come directly from the client + * because we reuse some of them for internal stuff + */ + create_options &= ~NTCREATEX_OPTIONS_MUST_IGNORE_MASK; /* * If it's an IPC, use the pipe handler. @@ -562,179 +504,31 @@ void reply_ntcreate_and_X(connection_struct *conn, do_ntcreate_pipe_open(conn, req); END_PROFILE(SMBntcreateX); return; - } else { - reply_doserror(req, ERRDOS, ERRnoaccess); - END_PROFILE(SMBntcreateX); - return; } - } - - if (create_options & FILE_OPEN_BY_FILE_ID) { - reply_nterror(req, NT_STATUS_NOT_SUPPORTED); + reply_doserror(req, ERRDOS, ERRnoaccess); END_PROFILE(SMBntcreateX); return; } - /* - * Get the file name. - */ - - if(root_dir_fid != 0) { - /* - * This filename is relative to a directory fid. - */ - char *rel_fname = NULL; - files_struct *dir_fsp = file_fsp( - SVAL(req->inbuf, smb_ntcreate_RootDirectoryFid)); - - if(!dir_fsp) { - reply_doserror(req, ERRDOS, ERRbadfid); - END_PROFILE(SMBntcreateX); - return; - } - - if(!dir_fsp->is_directory) { - - srvstr_get_path(ctx, (char *)req->inbuf, - req->flags2, &fname, - smb_buf(req->inbuf), 0, - STR_TERMINATE, &status); - if (!NT_STATUS_IS_OK(status)) { - reply_nterror(req, status); - END_PROFILE(SMBntcreateX); - return; - } - - /* - * Check to see if this is a mac fork of some kind. - */ - - if( is_ntfs_stream_name(fname)) { - reply_nterror( - req, NT_STATUS_OBJECT_PATH_NOT_FOUND); - END_PROFILE(SMBntcreateX); - return; - } - - /* - we need to handle the case when we get a - relative open relative to a file and the - pathname is blank - this is a reopen! - (hint from demyn plantenberg) - */ - - reply_doserror(req, ERRDOS, ERRbadfid); - END_PROFILE(SMBntcreateX); - return; - } - - if (ISDOT(dir_fsp->fsp_name)) { - /* - * We're at the toplevel dir, the final file name - * must not contain ./, as this is filtered out - * normally by srvstr_get_path and unix_convert - * explicitly rejects paths containing ./. - */ - fname = talloc_strdup(ctx,""); - if (!fname) { - reply_nterror(req, NT_STATUS_NO_MEMORY); - END_PROFILE(SMBntcreateX); - return; - } - } else { - size_t dir_name_len = strlen(dir_fsp->fsp_name); - - /* - * Copy in the base directory name. - */ - - fname = TALLOC_ARRAY(ctx, char, dir_name_len+2); - if (!fname) { - reply_nterror( - req, NT_STATUS_NO_MEMORY); - END_PROFILE(SMBntcreateX); - return; - } - memcpy(fname, dir_fsp->fsp_name, dir_name_len+1); - - /* - * Ensure it ends in a '/'. - * We used TALLOC_SIZE +2 to add space for the '/'. - */ - - if(dir_name_len && - (fname[dir_name_len-1] != '\\') && - (fname[dir_name_len-1] != '/')) { - fname[dir_name_len] = '/'; - fname[dir_name_len+1] = '\0'; - } - } - - srvstr_get_path(ctx, (char *)req->inbuf, req->flags2, &rel_fname, - smb_buf(req->inbuf), 0, - STR_TERMINATE, &status); - if (!NT_STATUS_IS_OK(status)) { - reply_nterror(req, status); - END_PROFILE(SMBntcreateX); - return; - } - fname = talloc_asprintf(ctx, "%s%s", - fname, - rel_fname); - if (!fname) { - reply_nterror( - req, NT_STATUS_NO_MEMORY); - END_PROFILE(SMBntcreateX); - return; - } - } else { - srvstr_get_path(ctx, (char *)req->inbuf, req->flags2, &fname, - smb_buf(req->inbuf), 0, - STR_TERMINATE, &status); - if (!NT_STATUS_IS_OK(status)) { - reply_nterror(req, status); - END_PROFILE(SMBntcreateX); - return; - } + oplock_request = (flags & REQUEST_OPLOCK) ? EXCLUSIVE_OPLOCK : 0; + if (oplock_request) { + oplock_request |= (flags & REQUEST_BATCH_OPLOCK) + ? BATCH_OPLOCK : 0; + } - /* - * Check to see if this is a mac fork of some kind. - */ + status = create_file(conn, req, root_dir_fid, fname, + access_mask, share_access, create_disposition, + create_options, file_attributes, oplock_request, + allocation_size, NULL, NULL, &fsp, &info, &sbuf); - if( is_ntfs_stream_name(fname)) { - enum FAKE_FILE_TYPE fake_file_type = is_fake_file(fname); - if (fake_file_type!=FAKE_FILE_TYPE_NONE) { - /* - * Here we go! support for changing the disk quotas --metze - * - * We need to fake up to open this MAGIC QUOTA file - * and return a valid FID. - * - * w2k close this file directly after openening - * xp also tries a QUERY_FILE_INFO on the file and then close it - */ - reply_ntcreate_and_X_quota(conn, req, - fake_file_type, fname); - } else { - reply_nterror(req, NT_STATUS_OBJECT_PATH_NOT_FOUND); - } + if (!NT_STATUS_IS_OK(status)) { + if (open_was_deferred(req->mid)) { + /* We have re-scheduled this call, no error. */ END_PROFILE(SMBntcreateX); return; } - } - - /* - * Now contruct the smb_open_mode value from the filename, - * desired access and the share access. - */ - status = resolve_dfspath(ctx, conn, - req->flags2 & FLAGS2_DFS_PATHNAMES, - fname, - &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); + if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) { + reply_botherror(req, status, ERRDOS, ERRfilexists); } else { reply_nterror(req, status); @@ -743,229 +537,36 @@ void reply_ntcreate_and_X(connection_struct *conn, return; } - oplock_request = (flags & REQUEST_OPLOCK) ? EXCLUSIVE_OPLOCK : 0; - if (oplock_request) { - oplock_request |= (flags & REQUEST_BATCH_OPLOCK) ? BATCH_OPLOCK : 0; - } - - /* - * Ordinary file or directory. - */ - - /* - * Check if POSIX semantics are wanted. - */ - - if (file_attributes & FILE_FLAG_POSIX_SEMANTICS) { - case_state = set_posix_case_semantics(NULL, conn); - file_attributes &= ~FILE_FLAG_POSIX_SEMANTICS; - } - - status = unix_convert(ctx, conn, fname, False, &fname, NULL, &sbuf); - if (!NT_STATUS_IS_OK(status)) { - TALLOC_FREE(case_state); - reply_nterror(req, status); - END_PROFILE(SMBntcreateX); - return; - } - /* All file access must go through check_name() */ - status = check_name(conn, fname); - if (!NT_STATUS_IS_OK(status)) { - TALLOC_FREE(case_state); - reply_nterror(req, status); - END_PROFILE(SMBntcreateX); - return; - } - - /* This is the correct thing to do (check every time) but can_delete is - expensive (it may have to read the parent directory permissions). So - for now we're not doing it unless we have a strong hint the client - is really going to delete this file. If the client is forcing FILE_CREATE - let the filesystem take care of the permissions. */ - - /* Setting FILE_SHARE_DELETE is the hint. */ - - if (lp_acl_check_permissions(SNUM(conn)) - && (create_disposition != FILE_CREATE) - && (share_access & FILE_SHARE_DELETE) - && (access_mask & DELETE_ACCESS)) { - if ((dos_mode(conn, fname, &sbuf) & FILE_ATTRIBUTE_READONLY) || - !can_delete_file_in_directory(conn, fname)) { - TALLOC_FREE(case_state); - reply_nterror(req, NT_STATUS_ACCESS_DENIED); - END_PROFILE(SMBntcreateX); - return; - } - } - -#if 0 - /* We need to support SeSecurityPrivilege for this. */ - if ((access_mask & SEC_RIGHT_SYSTEM_SECURITY) && - !user_has_privileges(current_user.nt_user_token, - &se_security)) { - TALLOC_FREE(case_state); - END_PROFILE(SMBntcreateX); - return ERROR_NT(NT_STATUS_PRIVILEGE_NOT_HELD); - } -#endif - /* - * If it's a request for a directory open, deal with it separately. + * If the caller set the extended oplock request bit + * and we granted one (by whatever means) - set the + * correct bit for extended oplock reply. */ - if(create_options & FILE_DIRECTORY_FILE) { - - /* Can't open a temp directory. IFS kit test. */ - if (file_attributes & FILE_ATTRIBUTE_TEMPORARY) { - TALLOC_FREE(case_state); - reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - END_PROFILE(SMBntcreateX); - return; - } - - oplock_request = 0; - status = open_directory(conn, req, fname, &sbuf, - access_mask, - share_access, - create_disposition, - create_options, - file_attributes, - &info, &fsp); - - } else { + if (oplock_request && + (lp_fake_oplocks(SNUM(conn)) + || EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type))) { /* - * Ordinary file case. + * Exclusive oplock granted */ - /* NB. We have a potential bug here. If we - * cause an oplock break to ourselves, then we - * could end up processing filename related - * SMB requests whilst we await the oplock - * break response. As we may have changed the - * filename case semantics to be POSIX-like, - * this could mean a filename request could - * fail when it should succeed. This is a rare - * condition, but eventually we must arrange - * to restore the correct case semantics - * before issuing an oplock break request to - * our client. JRA. */ - - status = open_file_ntcreate(conn, req, fname, &sbuf, - access_mask, - share_access, - create_disposition, - create_options, - file_attributes, - oplock_request, - &info, &fsp); - - /* We cheat here. There are two cases we - * care about. One is a directory rename, - * where the NT client will attempt to - * open the source directory for - * DELETE access. Note that when the - * NT client does this it does *not* - * set the directory bit in the - * request packet. This is translated - * into a read/write open - * request. POSIX states that any open - * for write request on a directory - * will generate an EISDIR error, so - * we can catch this here and open a - * pseudo handle that is flagged as a - * directory. The second is an open - * for a permissions read only, which - * we handle in the open_file_stat case. JRA. - */ - - if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_IS_A_DIRECTORY)) { - - /* - * Fail the open if it was explicitly a non-directory - * file. - */ - - if (create_options & FILE_NON_DIRECTORY_FILE) { - TALLOC_FREE(case_state); - reply_force_nterror(req, - NT_STATUS_FILE_IS_A_DIRECTORY); - END_PROFILE(SMBntcreateX); - return; - } - - oplock_request = 0; - status = open_directory(conn, req, fname, - &sbuf, - access_mask, - share_access, - create_disposition, - create_options, - file_attributes, - &info, &fsp); - } - } - - TALLOC_FREE(case_state); - - if (!NT_STATUS_IS_OK(status)) { - if (open_was_deferred(req->mid)) { - /* We have re-scheduled this call. */ - END_PROFILE(SMBntcreateX); - return; + if (flags & REQUEST_BATCH_OPLOCK) { + oplock_granted = BATCH_OPLOCK_RETURN; + } else { + oplock_granted = EXCLUSIVE_OPLOCK_RETURN; } - reply_openerror(req, status); - END_PROFILE(SMBntcreateX); - return; + } else if (fsp->oplock_type == LEVEL_II_OPLOCK) { + oplock_granted = LEVEL_II_OPLOCK_RETURN; + } else { + oplock_granted = NO_OPLOCK_RETURN; } file_len = sbuf.st_size; - fattr = dos_mode(conn,fname,&sbuf); - if(fattr == 0) { + fattr = dos_mode(conn,fsp->fsp_name,&sbuf); + if (fattr == 0) { fattr = FILE_ATTRIBUTE_NORMAL; } - if (!fsp->is_directory && (fattr & aDIR)) { - close_file(fsp,ERROR_CLOSE); - reply_doserror(req, ERRDOS, ERRnoaccess); - END_PROFILE(SMBntcreateX); - return; - } - - /* Save the requested allocation size. */ - if ((info == FILE_WAS_CREATED) || (info == FILE_WAS_OVERWRITTEN)) { - if (allocation_size && (allocation_size > (SMB_BIG_UINT)file_len)) { - fsp->initial_allocation_size = smb_roundup(fsp->conn, allocation_size); - if (fsp->is_directory) { - close_file(fsp,ERROR_CLOSE); - /* Can't set allocation size on a directory. */ - reply_nterror(req, NT_STATUS_ACCESS_DENIED); - END_PROFILE(SMBntcreateX); - return; - } - if (vfs_allocate_file_space(fsp, fsp->initial_allocation_size) == -1) { - close_file(fsp,ERROR_CLOSE); - reply_nterror(req, NT_STATUS_DISK_FULL); - END_PROFILE(SMBntcreateX); - return; - } - } else { - fsp->initial_allocation_size = smb_roundup(fsp->conn,(SMB_BIG_UINT)file_len); - } - } - - /* - * If the caller set the extended oplock request bit - * and we granted one (by whatever means) - set the - * correct bit for extended oplock reply. - */ - - if (oplock_request && lp_fake_oplocks(SNUM(conn))) { - extended_oplock_granted = True; - } - - if(oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) { - extended_oplock_granted = True; - } if (flags & EXTENDED_RESPONSE_REQUIRED) { /* This is very strange. We @@ -981,27 +582,13 @@ void reply_ntcreate_and_X(connection_struct *conn, p = (char *)req->outbuf + smb_vwv2; - /* - * Currently as we don't support level II oplocks we just report - * exclusive & batch here. - */ - - if (extended_oplock_granted) { - if (flags & REQUEST_BATCH_OPLOCK) { - SCVAL(p,0, BATCH_OPLOCK_RETURN); - } else { - SCVAL(p,0, EXCLUSIVE_OPLOCK_RETURN); - } - } else if (fsp->oplock_type == LEVEL_II_OPLOCK) { - SCVAL(p,0, LEVEL_II_OPLOCK_RETURN); - } else { - SCVAL(p,0,NO_OPLOCK_RETURN); - } + SCVAL(p, 0, oplock_granted); p++; SSVAL(p,0,fsp->fnum); p += 2; - if ((create_disposition == FILE_SUPERSEDE) && (info == FILE_WAS_OVERWRITTEN)) { + if ((create_disposition == FILE_SUPERSEDE) + && (info == FILE_WAS_OVERWRITTEN)) { SIVAL(p,0,FILE_WAS_SUPERSEDED); } else { SIVAL(p,0,info); @@ -1009,7 +596,8 @@ void reply_ntcreate_and_X(connection_struct *conn, p += 4; /* Create time. */ - c_timespec = get_create_timespec(&sbuf,lp_fake_dir_create_times(SNUM(conn))); + c_timespec = get_create_timespec( + &sbuf,lp_fake_dir_create_times(SNUM(conn))); a_timespec = get_atimespec(&sbuf); m_timespec = get_mtimespec(&sbuf); @@ -1042,7 +630,8 @@ void reply_ntcreate_and_X(connection_struct *conn, if (flags & EXTENDED_RESPONSE_REQUIRED) { uint32 perms = 0; p += 25; - if (fsp->is_directory || can_write_to_file(conn, fname, &sbuf)) { + if (fsp->is_directory + || can_write_to_file(conn, fsp->fsp_name, &sbuf)) { perms = FILE_GENERIC_ALL; } else { perms = FILE_GENERIC_READ|FILE_EXECUTE; @@ -1050,7 +639,8 @@ void reply_ntcreate_and_X(connection_struct *conn, SIVAL(p,0,perms); } - DEBUG(5,("reply_ntcreate_and_X: fnum = %d, open name = %s\n", fsp->fnum, fsp->fsp_name)); + DEBUG(5,("reply_ntcreate_and_X: fnum = %d, open name = %s\n", + fsp->fnum, fsp->fsp_name)); chain_reply(req); END_PROFILE(SMBntcreateX); @@ -1148,7 +738,7 @@ static void do_nt_transact_create_pipe(connection_struct *conn, DEBUG(5,("do_nt_transact_create_pipe: open name = %s\n", fname)); /* Send the required number of replies */ - send_nt_replies(req, NT_STATUS_OK, params, param_len, *ppdata, 0); + send_nt_replies(conn, req, NT_STATUS_OK, params, param_len, *ppdata, 0); return; } @@ -1157,46 +747,20 @@ static void do_nt_transact_create_pipe(connection_struct *conn, Internal fn to set security descriptors. ****************************************************************************/ -static NTSTATUS set_sd(files_struct *fsp, char *data, uint32 sd_len, uint32 security_info_sent) +static NTSTATUS set_sd(files_struct *fsp, uint8 *data, uint32 sd_len, + uint32 security_info_sent) { - prs_struct pd; SEC_DESC *psd = NULL; - TALLOC_CTX *mem_ctx; NTSTATUS status; if (sd_len == 0 || !lp_nt_acl_support(SNUM(fsp->conn))) { return NT_STATUS_OK; } - /* - * Init the parse struct we will unmarshall from. - */ - - if ((mem_ctx = talloc_init("set_sd")) == NULL) { - DEBUG(0,("set_sd: talloc_init failed.\n")); - return NT_STATUS_NO_MEMORY; - } - - prs_init(&pd, 0, mem_ctx, UNMARSHALL); - - /* - * Setup the prs_struct to point at the memory we just - * allocated. - */ - - prs_give_memory( &pd, data, sd_len, False); - - /* - * Finally, unmarshall from the data buffer. - */ + status = unmarshall_sec_desc(talloc_tos(), data, sd_len, &psd); - if(!sec_io_desc( "sd data", &psd, &pd, 1)) { - DEBUG(0,("set_sd: Error in unmarshalling security descriptor.\n")); - /* - * Return access denied for want of a better error message.. - */ - talloc_destroy(mem_ctx); - return NT_STATUS_NO_MEMORY; + if (!NT_STATUS_IS_OK(status)) { + return status; } if (psd->owner_sid==0) { @@ -1212,9 +776,16 @@ static NTSTATUS set_sd(files_struct *fsp, char *data, uint32 sd_len, uint32 secu security_info_sent &= ~DACL_SECURITY_INFORMATION; } - status = SMB_VFS_FSET_NT_ACL( fsp, fsp->fh->fd, security_info_sent, psd); + if (fsp->fh->fd != -1) { + status = SMB_VFS_FSET_NT_ACL(fsp, security_info_sent, psd); + } + else { + status = SMB_VFS_SET_NT_ACL(fsp, fsp->fsp_name, + security_info_sent, psd); + } + + TALLOC_FREE(psd); - talloc_destroy(mem_ctx); return status; } @@ -1240,406 +811,180 @@ static struct ea_list *read_nttrans_ea_list(TALLOC_CTX *ctx, const char *pdata, } DLIST_ADD_END(ea_list_head, eal, struct ea_list *); - if (next_offset == 0) { - break; - } - offset += next_offset; - } - - return ea_list_head; -} - -/**************************************************************************** - Reply to a NT_TRANSACT_CREATE call (needs to process SD's). -****************************************************************************/ - -static void call_nt_transact_create(connection_struct *conn, - struct smb_request *req, - uint16 **ppsetup, uint32 setup_count, - char **ppparams, uint32 parameter_count, - char **ppdata, uint32 data_count, - uint32 max_data_count) -{ - char *fname = NULL; - char *params = *ppparams; - char *data = *ppdata; - /* Breakout the oplock request bits so we can set the reply bits separately. */ - int oplock_request = 0; - uint32 fattr=0; - SMB_OFF_T file_len = 0; - SMB_STRUCT_STAT sbuf; - int info = 0; - files_struct *fsp = NULL; - char *p = NULL; - bool extended_oplock_granted = False; - uint32 flags; - uint32 access_mask; - uint32 file_attributes; - uint32 share_access; - uint32 create_disposition; - uint32 create_options; - uint32 sd_len; - uint32 ea_len; - uint16 root_dir_fid; - struct timespec c_timespec; - struct timespec a_timespec; - struct timespec m_timespec; - struct ea_list *ea_list = NULL; - char *pdata = NULL; - NTSTATUS status; - size_t param_len; - struct case_semantics_state *case_state = NULL; - TALLOC_CTX *ctx = talloc_tos(); - - DEBUG(5,("call_nt_transact_create\n")); - - /* - * If it's an IPC, use the pipe handler. - */ - - if (IS_IPC(conn)) { - if (lp_nt_pipe_support()) { - do_nt_transact_create_pipe( - conn, req, - ppsetup, setup_count, - ppparams, parameter_count, - ppdata, data_count); - return; - } else { - reply_doserror(req, ERRDOS, ERRnoaccess); - return; - } - } - - /* - * Ensure minimum number of parameters sent. - */ - - 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; - } - - flags = IVAL(params,0); - access_mask = IVAL(params,8); - file_attributes = IVAL(params,20); - share_access = IVAL(params,24); - create_disposition = IVAL(params,28); - create_options = IVAL(params,32); - sd_len = IVAL(params,36); - ea_len = IVAL(params,40); - root_dir_fid = (uint16)IVAL(params,4); - - /* Ensure the data_len is correct for the sd and ea values given. */ - if ((ea_len + sd_len > data_count) || - (ea_len > data_count) || (sd_len > data_count) || - (ea_len + sd_len < ea_len) || (ea_len + sd_len < sd_len)) { - DEBUG(10,("call_nt_transact_create - ea_len = %u, sd_len = %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; - } - - if (ea_len) { - if (!lp_ea_support(SNUM(conn))) { - DEBUG(10,("call_nt_transact_create - ea_len = %u but EA's not supported.\n", - (unsigned int)ea_len )); - reply_nterror(req, NT_STATUS_EAS_NOT_SUPPORTED); - return; - } - - if (ea_len < 10) { - DEBUG(10,("call_nt_transact_create - ea_len = %u - too small (should be more than 10)\n", - (unsigned int)ea_len )); - reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - return; - } - } - - if (create_options & FILE_OPEN_BY_FILE_ID) { - reply_nterror(req, NT_STATUS_NOT_SUPPORTED); - return; - } - - /* - * Get the file name. - */ - - if(root_dir_fid != 0) { - /* - * This filename is relative to a directory fid. - */ - char *tmpname = NULL; - files_struct *dir_fsp = file_fsp(SVAL(params,4)); - - if(!dir_fsp) { - reply_doserror(req, ERRDOS, ERRbadfid); - return; - } - - if(!dir_fsp->is_directory) { - srvstr_get_path(ctx, params, req->flags2, &fname, - params+53, - parameter_count-53, STR_TERMINATE, - &status); - if (!NT_STATUS_IS_OK(status)) { - reply_nterror(req, status); - return; - } - - /* - * Check to see if this is a mac fork of some kind. - */ - - if( is_ntfs_stream_name(fname)) { - reply_nterror(req, - NT_STATUS_OBJECT_PATH_NOT_FOUND); - return; - } - - reply_doserror(req, ERRDOS, ERRbadfid); - return; - } - - if (ISDOT(dir_fsp->fsp_name)) { - /* - * We're at the toplevel dir, the final file name - * must not contain ./, as this is filtered out - * normally by srvstr_get_path and unix_convert - * explicitly rejects paths containing ./. - */ - fname = talloc_strdup(ctx,""); - if (!fname) { - reply_nterror(req, NT_STATUS_NO_MEMORY); - return; - } - } else { - size_t dir_name_len = strlen(dir_fsp->fsp_name); - - /* - * Copy in the base directory name. - */ - - fname = TALLOC_ARRAY(ctx, char, dir_name_len+2); - if (!fname) { - reply_nterror(req, NT_STATUS_NO_MEMORY); - return; - } - memcpy(fname, dir_fsp->fsp_name, dir_name_len+1); - - /* - * Ensure it ends in a '/'. - * We used TALLOC_SIZE +2 to add space for the '/'. - */ - - if(dir_name_len && - (fname[dir_name_len-1] != '\\') && - (fname[dir_name_len-1] != '/')) { - fname[dir_name_len] = '/'; - fname[dir_name_len+1] = '\0'; - } - } - - srvstr_get_path(ctx, params, req->flags2, &tmpname, - params+53, - parameter_count-53, STR_TERMINATE, - &status); - if (!NT_STATUS_IS_OK(status)) { - reply_nterror(req, status); - return; - } - fname = talloc_asprintf(ctx, "%s%s", - fname, - tmpname); - if (!fname) { - reply_nterror( - req, NT_STATUS_NO_MEMORY); - return; - } - } else { - srvstr_get_path(ctx, params, req->flags2, &fname, params+53, - parameter_count-53, - STR_TERMINATE, &status); - if (!NT_STATUS_IS_OK(status)) { - reply_nterror(req, status); - return; - } - - /* - * Check to see if this is a mac fork of some kind. - */ - - if( is_ntfs_stream_name(fname)) { - reply_nterror(req, NT_STATUS_OBJECT_PATH_NOT_FOUND); - return; + if (next_offset == 0) { + break; } + offset += next_offset; } - oplock_request = (flags & REQUEST_OPLOCK) ? EXCLUSIVE_OPLOCK : 0; - if (oplock_request) { - oplock_request |= (flags & REQUEST_BATCH_OPLOCK) ? BATCH_OPLOCK : 0; - } + return ea_list_head; +} - /* - * Ordinary file or directory. - */ +/**************************************************************************** + Reply to a NT_TRANSACT_CREATE call (needs to process SD's). +****************************************************************************/ + +static void call_nt_transact_create(connection_struct *conn, + struct smb_request *req, + uint16 **ppsetup, uint32 setup_count, + char **ppparams, uint32 parameter_count, + char **ppdata, uint32 data_count, + uint32 max_data_count) +{ + 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; + uint32 flags; + uint32 access_mask; + uint32 file_attributes; + uint32 share_access; + uint32 create_disposition; + uint32 create_options; + uint32 sd_len; + struct security_descriptor *sd = NULL; + uint32 ea_len; + uint16 root_dir_fid; + struct timespec c_timespec; + struct timespec a_timespec; + struct timespec m_timespec; + struct ea_list *ea_list = NULL; + NTSTATUS status; + size_t param_len; + SMB_BIG_UINT allocation_size; + int oplock_request; + uint8_t oplock_granted; + TALLOC_CTX *ctx = talloc_tos(); + + DEBUG(5,("call_nt_transact_create\n")); /* - * Check if POSIX semantics are wanted. + * If it's an IPC, use the pipe handler. */ - if (file_attributes & FILE_FLAG_POSIX_SEMANTICS) { - case_state = set_posix_case_semantics(NULL, conn); - file_attributes &= ~FILE_FLAG_POSIX_SEMANTICS; - } - - status = resolve_dfspath(ctx, conn, - req->flags2 & FLAGS2_DFS_PATHNAMES, - fname, - &fname); - if (!NT_STATUS_IS_OK(status)) { - TALLOC_FREE(case_state); - if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { - reply_botherror(req, NT_STATUS_PATH_NOT_COVERED, - ERRSRV, ERRbadpath); + if (IS_IPC(conn)) { + if (lp_nt_pipe_support()) { + do_nt_transact_create_pipe( + conn, req, + ppsetup, setup_count, + ppparams, parameter_count, + ppdata, data_count); return; } - reply_nterror(req, status); + reply_doserror(req, ERRDOS, ERRnoaccess); return; } - status = unix_convert(ctx, conn, fname, False, &fname, NULL, &sbuf); - if (!NT_STATUS_IS_OK(status)) { - TALLOC_FREE(case_state); - reply_nterror(req, status); + /* + * Ensure minimum number of parameters sent. + */ + + 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; } - /* All file access must go through check_name() */ - status = check_name(conn, fname); - if (!NT_STATUS_IS_OK(status)) { - TALLOC_FREE(case_state); - reply_nterror(req, status); + + flags = IVAL(params,0); + access_mask = IVAL(params,8); + file_attributes = IVAL(params,20); + share_access = IVAL(params,24); + create_disposition = IVAL(params,28); + create_options = IVAL(params,32); + sd_len = IVAL(params,36); + ea_len = IVAL(params,40); + root_dir_fid = (uint16)IVAL(params,4); + allocation_size = (SMB_BIG_UINT)IVAL(params,12); +#ifdef LARGE_SMB_OFF_T + allocation_size |= (((SMB_BIG_UINT)IVAL(params,16)) << 32); +#endif + + /* + * we need to remove ignored bits when they come directly from the client + * because we reuse some of them for internal stuff + */ + create_options &= ~NTCREATEX_OPTIONS_MUST_IGNORE_MASK; + + /* Ensure the data_len is correct for the sd and ea values given. */ + if ((ea_len + sd_len > data_count) + || (ea_len > data_count) || (sd_len > data_count) + || (ea_len + sd_len < ea_len) || (ea_len + sd_len < sd_len)) { + DEBUG(10, ("call_nt_transact_create - ea_len = %u, sd_len = " + "%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; } - /* This is the correct thing to do (check every time) but can_delete is - expensive (it may have to read the parent directory permissions). So - for now we're not doing it unless we have a strong hint the client - is really going to delete this file. If the client is forcing FILE_CREATE - let the filesystem take care of the permissions. */ - - /* Setting FILE_SHARE_DELETE is the hint. */ + if (sd_len) { + DEBUG(10, ("call_nt_transact_create - sd_len = %d\n", + sd_len)); - if (lp_acl_check_permissions(SNUM(conn)) - && (create_disposition != FILE_CREATE) - && (share_access & FILE_SHARE_DELETE) - && (access_mask & DELETE_ACCESS)) { - if ((dos_mode(conn, fname, &sbuf) & FILE_ATTRIBUTE_READONLY) || - !can_delete_file_in_directory(conn, fname)) { - TALLOC_FREE(case_state); - reply_nterror(req, NT_STATUS_ACCESS_DENIED); + status = unmarshall_sec_desc(ctx, (uint8_t *)data, sd_len, + &sd); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(10, ("call_nt_transact_create: " + "unmarshall_sec_desc failed: %s\n", + nt_errstr(status))); + reply_nterror(req, status); return; } } -#if 0 - /* We need to support SeSecurityPrivilege for this. */ - if ((access_mask & SEC_RIGHT_SYSTEM_SECURITY) && - !user_has_privileges(current_user.nt_user_token, - &se_security)) { - TALLOC_FREE(case_state); - reply_nterror(req, NT_STATUS_PRIVILEGE_NOT_HELD); - return; - } -#endif - if (ea_len) { - pdata = data + sd_len; + if (!lp_ea_support(SNUM(conn))) { + DEBUG(10, ("call_nt_transact_create - ea_len = %u but " + "EA's not supported.\n", + (unsigned int)ea_len)); + reply_nterror(req, NT_STATUS_EAS_NOT_SUPPORTED); + return; + } - /* We have already checked that ea_len <= data_count here. */ - ea_list = read_nttrans_ea_list(talloc_tos(), pdata, - ea_len); - if (!ea_list ) { - TALLOC_FREE(case_state); + if (ea_len < 10) { + DEBUG(10,("call_nt_transact_create - ea_len = %u - " + "too small (should be more than 10)\n", + (unsigned int)ea_len )); reply_nterror(req, NT_STATUS_INVALID_PARAMETER); return; } - } - - /* - * If it's a request for a directory open, deal with it separately. - */ - if(create_options & FILE_DIRECTORY_FILE) { - - /* Can't open a temp directory. IFS kit test. */ - if (file_attributes & FILE_ATTRIBUTE_TEMPORARY) { - TALLOC_FREE(case_state); + /* We have already checked that ea_len <= data_count here. */ + ea_list = read_nttrans_ea_list(talloc_tos(), data + sd_len, + ea_len); + if (ea_list == NULL) { reply_nterror(req, NT_STATUS_INVALID_PARAMETER); return; } + } - /* - * We will get a create directory here if the Win32 - * app specified a security descriptor in the - * CreateDirectory() call. - */ - - oplock_request = 0; - status = open_directory(conn, req, fname, &sbuf, - access_mask, - share_access, - create_disposition, - create_options, - file_attributes, - &info, &fsp); - } else { - - /* - * Ordinary file case. - */ - - status = open_file_ntcreate(conn,req,fname,&sbuf, - access_mask, - share_access, - create_disposition, - create_options, - file_attributes, - oplock_request, - &info, &fsp); - - if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_IS_A_DIRECTORY)) { - - /* - * Fail the open if it was explicitly a non-directory file. - */ - - if (create_options & FILE_NON_DIRECTORY_FILE) { - TALLOC_FREE(case_state); - reply_force_nterror( - req, - NT_STATUS_FILE_IS_A_DIRECTORY); - return; - } + srvstr_get_path(ctx, params, req->flags2, &fname, + params+53, parameter_count-53, + STR_TERMINATE, &status); + if (!NT_STATUS_IS_OK(status)) { + reply_nterror(req, status); + return; + } - oplock_request = 0; - status = open_directory(conn, req, fname, - &sbuf, - access_mask, - share_access, - create_disposition, - create_options, - file_attributes, - &info, &fsp); - } + oplock_request = (flags & REQUEST_OPLOCK) ? EXCLUSIVE_OPLOCK : 0; + if (oplock_request) { + oplock_request |= (flags & REQUEST_BATCH_OPLOCK) + ? BATCH_OPLOCK : 0; } - TALLOC_FREE(case_state); + status = create_file(conn, req, root_dir_fid, fname, + access_mask, share_access, create_disposition, + create_options, file_attributes, oplock_request, + allocation_size, sd, ea_list, &fsp, &info, &sbuf); if(!NT_STATUS_IS_OK(status)) { if (open_was_deferred(req->mid)) { - /* We have re-scheduled this call. */ + /* We have re-scheduled this call, no error. */ return; } reply_openerror(req, status); @@ -1647,93 +992,35 @@ static void call_nt_transact_create(connection_struct *conn, } /* - * According to the MS documentation, the only time the security - * descriptor is applied to the opened file is iff we *created* the - * file; an existing file stays the same. - * - * Also, it seems (from observation) that you can open the file with - * any access mask but you can still write the sd. We need to override - * the granted access before we call set_sd - * Patch for bug #2242 from Tom Lackemann . + * If the caller set the extended oplock request bit + * and we granted one (by whatever means) - set the + * correct bit for extended oplock reply. */ - if (lp_nt_acl_support(SNUM(conn)) && sd_len && info == FILE_WAS_CREATED) { - uint32 saved_access_mask = fsp->access_mask; - - /* We have already checked that sd_len <= data_count here. */ - - fsp->access_mask = FILE_GENERIC_ALL; + if (oplock_request && + (lp_fake_oplocks(SNUM(conn)) + || EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type))) { - status = set_sd( fsp, data, sd_len, ALL_SECURITY_INFORMATION); - if (!NT_STATUS_IS_OK(status)) { - close_file(fsp,ERROR_CLOSE); - TALLOC_FREE(case_state); - reply_nterror(req, status); - return; - } - fsp->access_mask = saved_access_mask; - } + /* + * Exclusive oplock granted + */ - if (ea_len && (info == FILE_WAS_CREATED)) { - status = set_ea(conn, fsp, fname, ea_list); - if (!NT_STATUS_IS_OK(status)) { - close_file(fsp,ERROR_CLOSE); - TALLOC_FREE(case_state); - reply_nterror(req, status); - return; + if (flags & REQUEST_BATCH_OPLOCK) { + oplock_granted = BATCH_OPLOCK_RETURN; + } else { + oplock_granted = EXCLUSIVE_OPLOCK_RETURN; } + } else if (fsp->oplock_type == LEVEL_II_OPLOCK) { + oplock_granted = LEVEL_II_OPLOCK_RETURN; + } else { + oplock_granted = NO_OPLOCK_RETURN; } - TALLOC_FREE(case_state); - file_len = sbuf.st_size; - fattr = dos_mode(conn,fname,&sbuf); - if(fattr == 0) { + fattr = dos_mode(conn,fsp->fsp_name,&sbuf); + if (fattr == 0) { fattr = FILE_ATTRIBUTE_NORMAL; } - if (!fsp->is_directory && (fattr & aDIR)) { - close_file(fsp,ERROR_CLOSE); - reply_doserror(req, ERRDOS, ERRnoaccess); - return; - } - - /* Save the requested allocation size. */ - if ((info == FILE_WAS_CREATED) || (info == FILE_WAS_OVERWRITTEN)) { - SMB_BIG_UINT allocation_size = (SMB_BIG_UINT)IVAL(params,12); -#ifdef LARGE_SMB_OFF_T - allocation_size |= (((SMB_BIG_UINT)IVAL(params,16)) << 32); -#endif - if (allocation_size && (allocation_size > file_len)) { - fsp->initial_allocation_size = smb_roundup(fsp->conn, allocation_size); - if (fsp->is_directory) { - close_file(fsp,ERROR_CLOSE); - /* Can't set allocation size on a directory. */ - reply_nterror(req, NT_STATUS_ACCESS_DENIED); - return; - } - if (vfs_allocate_file_space(fsp, fsp->initial_allocation_size) == -1) { - close_file(fsp,ERROR_CLOSE); - reply_nterror(req, NT_STATUS_DISK_FULL); - return; - } - } else { - fsp->initial_allocation_size = smb_roundup(fsp->conn, (SMB_BIG_UINT)file_len); - } - } - - /* - * If the caller set the extended oplock request bit - * and we granted one (by whatever means) - set the - * correct bit for extended oplock reply. - */ - - if (oplock_request && lp_fake_oplocks(SNUM(conn))) { - extended_oplock_granted = True; - } - - if(oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) { - extended_oplock_granted = True; - } /* Realloc the size of parameters and data we will return */ if (flags & EXTENDED_RESPONSE_REQUIRED) { @@ -1749,22 +1036,13 @@ static void call_nt_transact_create(connection_struct *conn, } p = params; - if (extended_oplock_granted) { - if (flags & REQUEST_BATCH_OPLOCK) { - SCVAL(p,0, BATCH_OPLOCK_RETURN); - } else { - SCVAL(p,0, EXCLUSIVE_OPLOCK_RETURN); - } - } else if (fsp->oplock_type == LEVEL_II_OPLOCK) { - SCVAL(p,0, LEVEL_II_OPLOCK_RETURN); - } else { - SCVAL(p,0,NO_OPLOCK_RETURN); - } + SCVAL(p, 0, oplock_granted); p += 2; SSVAL(p,0,fsp->fnum); p += 2; - if ((create_disposition == FILE_SUPERSEDE) && (info == FILE_WAS_OVERWRITTEN)) { + if ((create_disposition == FILE_SUPERSEDE) + && (info == FILE_WAS_OVERWRITTEN)) { SIVAL(p,0,FILE_WAS_SUPERSEDED); } else { SIVAL(p,0,info); @@ -1772,7 +1050,8 @@ static void call_nt_transact_create(connection_struct *conn, p += 8; /* Create time. */ - c_timespec = get_create_timespec(&sbuf,lp_fake_dir_create_times(SNUM(conn))); + c_timespec = get_create_timespec( + &sbuf,lp_fake_dir_create_times(SNUM(conn))); a_timespec = get_atimespec(&sbuf); m_timespec = get_mtimespec(&sbuf); @@ -1805,7 +1084,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, fname, &sbuf)) { + if (fsp->is_directory + || can_write_to_file(conn, fsp->fsp_name, &sbuf)) { perms = FILE_GENERIC_ALL; } else { perms = FILE_GENERIC_READ|FILE_EXECUTE; @@ -1813,10 +1093,10 @@ static void call_nt_transact_create(connection_struct *conn, SIVAL(p,0,perms); } - DEBUG(5,("call_nt_transact_create: open name = %s\n", fname)); + DEBUG(5,("call_nt_transact_create: open name = %s\n", fsp->fsp_name)); /* Send the required number of replies */ - send_nt_replies(req, NT_STATUS_OK, params, param_len, *ppdata, 0); + send_nt_replies(conn, req, NT_STATUS_OK, params, param_len, *ppdata, 0); return; } @@ -1826,7 +1106,7 @@ static void call_nt_transact_create(connection_struct *conn, conn POINTER CAN BE NULL HERE ! ****************************************************************************/ -void reply_ntcancel(connection_struct *conn, struct smb_request *req) +void reply_ntcancel(struct smb_request *req) { /* * Go through and cancel any pending change notifies. @@ -1963,7 +1243,7 @@ static NTSTATUS copy_internals(TALLOC_CTX *ctx, close_file(fsp1,NORMAL_CLOSE); /* Ensure the modtime is set correctly on the destination file. */ - fsp_set_pending_modtime(fsp2, get_mtimespec(&sbuf1)); + set_close_write_time(fsp2, get_mtimespec(&sbuf1)); status = close_file(fsp2,NORMAL_CLOSE); @@ -1971,7 +1251,7 @@ static NTSTATUS copy_internals(TALLOC_CTX *ctx, creates the file. This isn't the correct thing to do in the copy case. JRA */ file_set_dosmode(conn, newname, fattr, &sbuf2, - parent_dirname(newname)); + parent_dirname(newname),false); if (ret < (SMB_OFF_T)sbuf1.st_size) { return NT_STATUS_DISK_FULL; @@ -1988,8 +1268,9 @@ static NTSTATUS copy_internals(TALLOC_CTX *ctx, Reply to a NT rename request. ****************************************************************************/ -void reply_ntrename(connection_struct *conn, struct smb_request *req) +void reply_ntrename(struct smb_request *req) { + connection_struct *conn = req->conn; char *oldname = NULL; char *newname = NULL; char *p; @@ -2082,7 +1363,7 @@ void reply_ntrename(connection_struct *conn, struct smb_request *req) case RENAME_FLAG_RENAME: status = rename_internals(ctx, conn, req, oldname, newname, attrs, False, src_has_wcard, - dest_has_wcard); + dest_has_wcard, DELETE_ACCESS); break; case RENAME_FLAG_HARD_LINK: if (src_has_wcard || dest_has_wcard) { @@ -2210,7 +1491,7 @@ static void call_nt_transact_notify_change(connection_struct *conn, * here. */ - change_notify_reply(req->inbuf, max_param_count, fsp->notify); + change_notify_reply(fsp->conn, req->inbuf, max_param_count, fsp->notify); /* * change_notify_reply() above has independently sent its @@ -2223,7 +1504,9 @@ static void call_nt_transact_notify_change(connection_struct *conn, * No changes pending, queue the request */ - status = change_notify_add_request(req->inbuf, max_param_count, filter, + status = change_notify_add_request(req, + max_param_count, + filter, recursive, fsp); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); @@ -2245,7 +1528,6 @@ static void call_nt_transact_rename(connection_struct *conn, char *params = *ppparams; char *new_name = NULL; files_struct *fsp = NULL; - bool replace_if_exists = False; bool dest_has_wcard = False; NTSTATUS status; TALLOC_CTX *ctx = talloc_tos(); @@ -2256,7 +1538,6 @@ static void call_nt_transact_rename(connection_struct *conn, } fsp = file_fsp(SVAL(params, 0)); - replace_if_exists = (SVAL(params,2) & RENAME_REPLACE_IF_EXISTS) ? True : False; if (!check_fsp(conn, req, fsp, ¤t_user)) { return; } @@ -2268,31 +1549,13 @@ static void call_nt_transact_rename(connection_struct *conn, return; } - status = rename_internals(ctx, - conn, - req, - fsp->fsp_name, - new_name, - 0, - replace_if_exists, - False, - dest_has_wcard); - - if (!NT_STATUS_IS_OK(status)) { - if (open_was_deferred(req->mid)) { - /* We have re-scheduled this call. */ - return; - } - reply_nterror(req, status); - return; - } - /* - * Rename was successful. + * W2K3 ignores this request as the RAW-RENAME test + * demonstrates, so we do. */ - send_nt_replies(req, NT_STATUS_OK, NULL, 0, NULL, 0); + send_nt_replies(conn, req, NT_STATUS_OK, NULL, 0, NULL, 0); - DEBUG(3,("nt transact rename from = %s, to = %s succeeded.\n", + DEBUG(3,("nt transact rename from = %s, to = %s ignored!\n", fsp->fsp_name, new_name)); return; @@ -2302,17 +1565,17 @@ static void call_nt_transact_rename(connection_struct *conn, Fake up a completely empty SD. *******************************************************************************/ -static size_t get_null_nt_acl(TALLOC_CTX *mem_ctx, SEC_DESC **ppsd) +static NTSTATUS get_null_nt_acl(TALLOC_CTX *mem_ctx, SEC_DESC **ppsd) { size_t sd_size; *ppsd = make_standard_sec_desc( mem_ctx, &global_sid_World, &global_sid_World, NULL, &sd_size); if(!*ppsd) { DEBUG(0,("get_null_nt_acl: Unable to malloc space for security descriptor.\n")); - sd_size = 0; + return NT_STATUS_NO_MEMORY; } - return sd_size; + return NT_STATUS_OK; } /**************************************************************************** @@ -2331,12 +1594,12 @@ static void call_nt_transact_query_security_desc(connection_struct *conn, { char *params = *ppparams; char *data = *ppdata; - prs_struct pd; SEC_DESC *psd = NULL; size_t sd_size; uint32 security_info_wanted; - TALLOC_CTX *mem_ctx; files_struct *fsp = NULL; + NTSTATUS status; + DATA_BLOB blob; if(parameter_count < 8) { reply_doserror(req, ERRDOS, ERRbadfunc); @@ -2360,37 +1623,37 @@ static void call_nt_transact_query_security_desc(connection_struct *conn, return; } - if ((mem_ctx = talloc_init("call_nt_transact_query_security_desc")) == NULL) { - DEBUG(0,("call_nt_transact_query_security_desc: talloc_init failed.\n")); - reply_doserror(req, ERRDOS, ERRnomem); - return; - } - /* * Get the permissions to return. */ if (!lp_nt_acl_support(SNUM(conn))) { - sd_size = get_null_nt_acl(mem_ctx, &psd); + status = get_null_nt_acl(talloc_tos(), &psd); } else { - sd_size = SMB_VFS_FGET_NT_ACL(fsp, fsp->fh->fd, security_info_wanted, &psd); + if (fsp->fh->fd != -1) { + status = SMB_VFS_FGET_NT_ACL( + fsp, security_info_wanted, &psd); + } + else { + status = SMB_VFS_GET_NT_ACL( + conn, fsp->fsp_name, security_info_wanted, &psd); + } } - if (sd_size == 0) { - talloc_destroy(mem_ctx); - reply_unixerror(req, ERRDOS, ERRnoaccess); + if (!NT_STATUS_IS_OK(status)) { + reply_nterror(req, status); return; } + sd_size = ndr_size_security_descriptor(psd, 0); + DEBUG(3,("call_nt_transact_query_security_desc: sd_size = %lu.\n",(unsigned long)sd_size)); SIVAL(params,0,(uint32)sd_size); - if(max_data_count < sd_size) { - - send_nt_replies(req, NT_STATUS_BUFFER_TOO_SMALL, + if (max_data_count < sd_size) { + send_nt_replies(conn, req, NT_STATUS_BUFFER_TOO_SMALL, params, 4, *ppdata, 0); - talloc_destroy(mem_ctx); return; } @@ -2400,46 +1663,23 @@ static void call_nt_transact_query_security_desc(connection_struct *conn, data = nttrans_realloc(ppdata, sd_size); if(data == NULL) { - talloc_destroy(mem_ctx); reply_doserror(req, ERRDOS, ERRnomem); return; } - /* - * Init the parse struct we will marshall into. - */ - - prs_init(&pd, 0, mem_ctx, MARSHALL); - - /* - * Setup the prs_struct to point at the memory we just - * allocated. - */ - - prs_give_memory( &pd, data, (uint32)sd_size, False); - - /* - * Finally, linearize into the outgoing buffer. - */ + status = marshall_sec_desc(talloc_tos(), psd, + &blob.data, &blob.length); - if(!sec_io_desc( "sd data", &psd, &pd, 1)) { - DEBUG(0,("call_nt_transact_query_security_desc: Error in marshalling \ -security descriptor.\n")); - /* - * Return access denied for want of a better error message.. - */ - talloc_destroy(mem_ctx); - reply_unixerror(req, ERRDOS, ERRnoaccess); + if (!NT_STATUS_IS_OK(status)) { + reply_nterror(req, status); return; } - /* - * Now we can delete the security descriptor. - */ + SMB_ASSERT(sd_size == blob.length); + memcpy(data, blob.data, sd_size); - talloc_destroy(mem_ctx); + send_nt_replies(conn, req, NT_STATUS_OK, params, 4, data, (int)sd_size); - send_nt_replies(req, NT_STATUS_OK, params, 4, data, (int)sd_size); return; } @@ -2461,7 +1701,7 @@ static void call_nt_transact_set_security_desc(connection_struct *conn, char *data = *ppdata; files_struct *fsp = NULL; uint32 security_info_sent = 0; - NTSTATUS nt_status; + NTSTATUS status; if(parameter_count < 8) { reply_doserror(req, ERRDOS, ERRbadfunc); @@ -2487,14 +1727,15 @@ static void call_nt_transact_set_security_desc(connection_struct *conn, return; } - if (!NT_STATUS_IS_OK(nt_status = set_sd( fsp, data, data_count, security_info_sent))) { - reply_nterror(req, nt_status); + status = set_sd(fsp, (uint8 *)data, data_count, security_info_sent); + + if (!NT_STATUS_IS_OK(status)) { + reply_nterror(req, status); return; } done: - - send_nt_replies(req, NT_STATUS_OK, NULL, 0, NULL, 0); + send_nt_replies(conn, req, NT_STATUS_OK, NULL, 0, NULL, 0); return; } @@ -2543,7 +1784,7 @@ static void call_nt_transact_ioctl(connection_struct *conn, so we can know if we need to pre-allocate or not */ DEBUG(10,("FSCTL_SET_SPARSE: called on FID[0x%04X](but not implemented)\n", fidnum)); - send_nt_replies(req, NT_STATUS_OK, NULL, 0, NULL, 0); + send_nt_replies(conn, req, NT_STATUS_OK, NULL, 0, NULL, 0); return; case FSCTL_CREATE_OR_GET_OBJECT_ID: @@ -2569,7 +1810,7 @@ static void call_nt_transact_ioctl(connection_struct *conn, push_file_id_16(pdata, &fsp->file_id); memcpy(pdata+16,create_volume_objectid(conn,objid),16); push_file_id_16(pdata+32, &fsp->file_id); - send_nt_replies(req, NT_STATUS_OK, NULL, 0, + send_nt_replies(conn, req, NT_STATUS_OK, NULL, 0, pdata, data_count); return; } @@ -2714,7 +1955,7 @@ static void call_nt_transact_ioctl(connection_struct *conn, talloc_destroy(shadow_data->mem_ctx); - send_nt_replies(req, NT_STATUS_OK, NULL, 0, + send_nt_replies(conn, req, NT_STATUS_OK, NULL, 0, pdata, data_count); return; @@ -2742,11 +1983,12 @@ static void call_nt_transact_ioctl(connection_struct *conn, /*unknown = IVAL(pdata,0);*/ sid_parse(pdata+4,sid_len,&sid); - DEBUGADD(10,("for SID: %s\n",sid_string_static(&sid))); + DEBUGADD(10, ("for SID: %s\n", sid_string_dbg(&sid))); if (!sid_to_uid(&sid, &uid)) { DEBUG(0,("sid_to_uid: failed, sid[%s] sid_len[%lu]\n", - sid_string_static(&sid),(unsigned long)sid_len)); + sid_string_dbg(&sid), + (unsigned long)sid_len)); uid = (-1); } @@ -2769,7 +2011,7 @@ static void call_nt_transact_ioctl(connection_struct *conn, */ /* this works for now... */ - send_nt_replies(req, NT_STATUS_OK, NULL, 0, NULL, 0); + send_nt_replies(conn, req, NT_STATUS_OK, NULL, 0, NULL, 0); return; } default: @@ -2923,7 +2165,8 @@ static void call_nt_transact_get_user_quota(connection_struct *conn, for (;((tmp_list!=NULL)&&((qt_len +40+SID_MAX_SIZE)next,entry+=entry_len,qt_len+=entry_len) { - sid_len = sid_size(&tmp_list->quotas->sid); + sid_len = ndr_size_dom_sid( + &tmp_list->quotas->sid, 0); entry_len = 40 + sid_len; /* nextoffset entry 4 bytes */ @@ -3054,7 +2297,7 @@ static void call_nt_transact_get_user_quota(connection_struct *conn, break; } - send_nt_replies(req, nt_status, params, param_len, + send_nt_replies(conn, req, nt_status, params, param_len, pdata, data_len); } @@ -3175,7 +2418,7 @@ static void call_nt_transact_set_user_quota(connection_struct *conn, #endif /* LARGE_SMB_OFF_T */ sid_parse(pdata+40,sid_len,&sid); - DEBUGADD(8,("SID: %s\n",sid_string_static(&sid))); + DEBUGADD(8,("SID: %s\n", sid_string_dbg(&sid))); /* 44 unknown bytes left... */ @@ -3184,7 +2427,7 @@ static void call_nt_transact_set_user_quota(connection_struct *conn, return; } - send_nt_replies(req, NT_STATUS_OK, params, param_len, + send_nt_replies(conn, req, NT_STATUS_OK, params, param_len, pdata, data_len); } #endif /* HAVE_SYS_QUOTAS */ @@ -3321,16 +2564,18 @@ static void handle_nttrans(connection_struct *conn, Reply to a SMBNTtrans. ****************************************************************************/ -void reply_nttrans(connection_struct *conn, struct smb_request *req) +void reply_nttrans(struct smb_request *req) { - uint32 pscnt; - uint32 psoff; - uint32 dscnt; - uint32 dsoff; + connection_struct *conn = req->conn; + uint32_t pscnt; + uint32_t psoff; + uint32_t dscnt; + uint32_t dsoff; uint16 function_code; NTSTATUS result; struct trans_state *state; - int size; + uint32_t size; + uint32_t av_size; START_PROFILE(SMBnttrans); @@ -3341,6 +2586,7 @@ void reply_nttrans(connection_struct *conn, struct smb_request *req) } size = smb_len(req->inbuf) + 4; + av_size = smb_len(req->inbuf); pscnt = IVAL(req->inbuf,smb_nt_ParameterCount); psoff = IVAL(req->inbuf,smb_nt_ParameterOffset); dscnt = IVAL(req->inbuf,smb_nt_DataCount); @@ -3416,12 +2662,17 @@ void reply_nttrans(connection_struct *conn, struct smb_request *req) END_PROFILE(SMBnttrans); return; } - if ((dsoff+dscnt < dsoff) || (dsoff+dscnt < dscnt)) + + if (dscnt > state->total_data || + dsoff+dscnt < dsoff) { goto bad_param; - if ((smb_base(req->inbuf)+dsoff+dscnt - > (char *)req->inbuf + size) || - (smb_base(req->inbuf)+dsoff+dscnt < smb_base(req->inbuf))) + } + + if (dsoff > av_size || + dscnt > av_size || + dsoff+dscnt > av_size) { goto bad_param; + } memcpy(state->data,smb_base(req->inbuf)+dsoff,dscnt); } @@ -3438,12 +2689,17 @@ void reply_nttrans(connection_struct *conn, struct smb_request *req) END_PROFILE(SMBnttrans); return; } - if ((psoff+pscnt < psoff) || (psoff+pscnt < pscnt)) + + if (pscnt > state->total_param || + psoff+pscnt < psoff) { goto bad_param; - if ((smb_base(req->inbuf)+psoff+pscnt - > (char *)req->inbuf + size) || - (smb_base(req->inbuf)+psoff+pscnt < smb_base(req->inbuf))) + } + + if (psoff > av_size || + pscnt > av_size || + psoff+pscnt > av_size) { goto bad_param; + } memcpy(state->param,smb_base(req->inbuf)+psoff,pscnt); } @@ -3512,12 +2768,13 @@ void reply_nttrans(connection_struct *conn, struct smb_request *req) Reply to a SMBnttranss ****************************************************************************/ -void reply_nttranss(connection_struct *conn, struct smb_request *req) +void reply_nttranss(struct smb_request *req) { - unsigned int pcnt,poff,dcnt,doff,pdisp,ddisp; + connection_struct *conn = req->conn; + uint32_t pcnt,poff,dcnt,doff,pdisp,ddisp; struct trans_state *state; - - int size; + uint32_t av_size; + uint32_t size; START_PROFILE(SMBnttranss); @@ -3554,6 +2811,7 @@ void reply_nttranss(connection_struct *conn, struct smb_request *req) } size = smb_len(req->inbuf) + 4; + av_size = smb_len(req->inbuf); pcnt = IVAL(req->inbuf,smb_nts_ParameterCount); poff = IVAL(req->inbuf, smb_nts_ParameterOffset); @@ -3571,38 +2829,38 @@ void reply_nttranss(connection_struct *conn, struct smb_request *req) goto bad_param; if (pcnt) { - if (pdisp+pcnt > state->total_param) + if (pdisp > state->total_param || + pcnt > state->total_param || + pdisp+pcnt > state->total_param || + pdisp+pcnt < pdisp) { goto bad_param; - if ((pdisp+pcnt < pdisp) || (pdisp+pcnt < pcnt)) - goto bad_param; - if (pdisp > state->total_param) - goto bad_param; - if ((smb_base(req->inbuf) + poff + pcnt - > (char *)req->inbuf + size) || - (smb_base(req->inbuf) + poff + pcnt - < smb_base(req->inbuf))) - goto bad_param; - if (state->param + pdisp < state->param) + } + + if (poff > av_size || + pcnt > av_size || + poff+pcnt > av_size || + poff+pcnt < poff) { goto bad_param; + } memcpy(state->param+pdisp, smb_base(req->inbuf)+poff, pcnt); } if (dcnt) { - if (ddisp+dcnt > state->total_data) - goto bad_param; - if ((ddisp+dcnt < ddisp) || (ddisp+dcnt < dcnt)) - goto bad_param; - if (ddisp > state->total_data) + if (ddisp > state->total_data || + dcnt > state->total_data || + ddisp+dcnt > state->total_data || + ddisp+dcnt < ddisp) { goto bad_param; - if ((smb_base(req->inbuf) + doff + dcnt - > (char *)req->inbuf + size) || - (smb_base(req->inbuf) + doff + dcnt - < smb_base(req->inbuf))) - goto bad_param; - if (state->data + ddisp < state->data) + } + + if (ddisp > av_size || + dcnt > av_size || + ddisp+dcnt > av_size || + ddisp+dcnt < ddisp) { goto bad_param; + } memcpy(state->data+ddisp, smb_base(req->inbuf)+doff, dcnt);