diff options
author | John H Terpstra <jht@samba.org> | 2009-07-23 09:33:06 -0500 |
---|---|---|
committer | John H Terpstra <jht@samba.org> | 2009-07-23 09:33:06 -0500 |
commit | 94717ae8e5dfe2ccdb7f3557d5490708b00ae471 (patch) | |
tree | a39f669faf23ad05497963cf5ccf611467d0145b /source3/smbd | |
parent | 14952c72a29ec92badb1bcf16d2a15fe100f060d (diff) | |
parent | 7bad4b48c82fed4263c2bfe97a4d00b47913604a (diff) | |
download | samba-94717ae8e5dfe2ccdb7f3557d5490708b00ae471.tar.gz samba-94717ae8e5dfe2ccdb7f3557d5490708b00ae471.tar.bz2 samba-94717ae8e5dfe2ccdb7f3557d5490708b00ae471.zip |
Merge branch 'master' of ssh://jht@git.samba.org/data/git/samba
Diffstat (limited to 'source3/smbd')
44 files changed, 3083 insertions, 2232 deletions
diff --git a/source3/smbd/aio.c b/source3/smbd/aio.c index c6f700f17a..ed415c5e13 100644 --- a/source3/smbd/aio.c +++ b/source3/smbd/aio.c @@ -188,7 +188,7 @@ bool schedule_aio_read_and_X(connection_struct *conn, DEBUG(10,("schedule_aio_read_and_X: scheduled aio_read for file %s, " "offset %.0f, len = %u (mid = %u)\n", - fsp->fsp_name, (double)startpos, (unsigned int)smb_maxcnt, + fsp_str_dbg(fsp), (double)startpos, (unsigned int)smb_maxcnt, (unsigned int)aio_ex->req->mid )); outstanding_aio_calls++; @@ -241,7 +241,7 @@ bool schedule_aio_write_and_X(connection_struct *conn, DEBUG(10,("schedule_aio_write_and_X: failed to schedule " "aio_write for file %s, offset %.0f, len = %u " "(mid = %u)\n", - fsp->fsp_name, (double)startpos, + fsp_str_dbg(fsp), (double)startpos, (unsigned int)numtowrite, (unsigned int)req->mid )); return False; @@ -300,14 +300,14 @@ bool schedule_aio_write_and_X(connection_struct *conn, "failed."); } DEBUG(10,("schedule_aio_write_and_X: scheduled aio_write " - "behind for file %s\n", fsp->fsp_name )); + "behind for file %s\n", fsp_str_dbg(fsp))); } outstanding_aio_calls++; DEBUG(10,("schedule_aio_write_and_X: scheduled aio_write for file " "%s, offset %.0f, len = %u (mid = %u) " "outstanding_aio_calls = %d\n", - fsp->fsp_name, (double)startpos, (unsigned int)numtowrite, + fsp_str_dbg(fsp), (double)startpos, (unsigned int)numtowrite, (unsigned int)aio_ex->req->mid, outstanding_aio_calls )); return True; @@ -341,7 +341,7 @@ static int handle_aio_read_complete(struct aio_extra *aio_ex) DEBUG( 3,( "handle_aio_read_complete: file %s nread == -1. " "Error = %s\n", - aio_ex->fsp->fsp_name, strerror(errno) )); + fsp_str_dbg(aio_ex->fsp), strerror(errno))); ret = errno; ERROR_NT(map_nt_error_from_unix(ret)); @@ -359,7 +359,7 @@ static int handle_aio_read_complete(struct aio_extra *aio_ex) DEBUG( 3, ( "handle_aio_read_complete file %s max=%d " "nread=%d\n", - aio_ex->fsp->fsp_name, + fsp_str_dbg(aio_ex->fsp), (int)aio_ex->acb.aio_nbytes, (int)nread ) ); } @@ -374,7 +374,7 @@ static int handle_aio_read_complete(struct aio_extra *aio_ex) DEBUG(10,("handle_aio_read_complete: scheduled aio_read completed " "for file %s, offset %.0f, len = %u\n", - aio_ex->fsp->fsp_name, (double)aio_ex->acb.aio_offset, + fsp_str_dbg(aio_ex->fsp), (double)aio_ex->acb.aio_offset, (unsigned int)nread )); return ret; @@ -399,13 +399,13 @@ static int handle_aio_write_complete(struct aio_extra *aio_ex) DEBUG(5,("handle_aio_write_complete: " "aio_write_behind failed ! File %s " "is corrupt ! Error %s\n", - fsp->fsp_name, strerror(errno) )); + fsp_str_dbg(fsp), strerror(errno))); ret = errno; } else { DEBUG(0,("handle_aio_write_complete: " "aio_write_behind failed ! File %s " "is corrupt ! Wanted %u bytes but " - "only wrote %d\n", fsp->fsp_name, + "only wrote %d\n", fsp_str_dbg(fsp), (unsigned int)numtowrite, (int)nwritten )); ret = EIO; @@ -413,7 +413,7 @@ static int handle_aio_write_complete(struct aio_extra *aio_ex) } else { DEBUG(10,("handle_aio_write_complete: " "aio_write_behind completed for file %s\n", - fsp->fsp_name )); + fsp_str_dbg(fsp))); } return 0; } @@ -424,7 +424,7 @@ static int handle_aio_write_complete(struct aio_extra *aio_ex) if(nwritten == -1) { DEBUG( 3,( "handle_aio_write: file %s wanted %u bytes. " "nwritten == %d. Error = %s\n", - fsp->fsp_name, (unsigned int)numtowrite, + fsp_str_dbg(fsp), (unsigned int)numtowrite, (int)nwritten, strerror(errno) )); /* If errno is ECANCELED then don't return anything to the @@ -456,7 +456,7 @@ static int handle_aio_write_complete(struct aio_extra *aio_ex) ERRHRD, ERRdiskfull); srv_set_message(outbuf,0,0,true); DEBUG(5,("handle_aio_write: sync_file for %s returned %s\n", - fsp->fsp_name, nt_errstr(status) )); + fsp_str_dbg(fsp), nt_errstr(status))); } aio_ex->fsp->fh->pos = aio_ex->acb.aio_offset + nwritten; @@ -472,7 +472,7 @@ static int handle_aio_write_complete(struct aio_extra *aio_ex) DEBUG(10,("handle_aio_write_complete: scheduled aio_write completed " "for file %s, offset %.0f, requested %u, written = %u\n", - fsp->fsp_name, (double)aio_ex->acb.aio_offset, + fsp_str_dbg(fsp), (double)aio_ex->acb.aio_offset, (unsigned int)numtowrite, (unsigned int)nwritten )); return ret; @@ -496,7 +496,7 @@ static bool handle_aio_completed(struct aio_extra *aio_ex, int *perr) if (SMB_VFS_AIO_ERROR(aio_ex->fsp, &aio_ex->acb) == EINPROGRESS) { DEBUG(10,( "handle_aio_completed: operation mid %u still in " "process for file %s\n", - aio_ex->req->mid, aio_ex->fsp->fsp_name )); + aio_ex->req->mid, fsp_str_dbg(aio_ex->fsp))); return False; } diff --git a/source3/smbd/blocking.c b/source3/smbd/blocking.c index 4c61428692..e752194ca5 100644 --- a/source3/smbd/blocking.c +++ b/source3/smbd/blocking.c @@ -202,7 +202,7 @@ bool push_blocking_lock_request( struct byte_range_lock *br_lck, "expiry time (%u sec. %u usec) (+%d msec) for fnum = %d, name = %s\n", (unsigned int)blr->expire_time.tv_sec, (unsigned int)blr->expire_time.tv_usec, lock_timeout, - blr->fsp->fnum, blr->fsp->fsp_name )); + blr->fsp->fnum, fsp_str_dbg(blr->fsp))); return True; } @@ -418,8 +418,9 @@ static bool process_lockingX(struct blocking_lock_record *blr) * Success - we got all the locks. */ - DEBUG(3,("process_lockingX file = %s, fnum=%d type=%d num_locks=%d\n", - fsp->fsp_name, fsp->fnum, (unsigned int)locktype, num_locks) ); + DEBUG(3,("process_lockingX file = %s, fnum=%d type=%d " + "num_locks=%d\n", fsp_str_dbg(fsp), fsp->fnum, + (unsigned int)locktype, num_locks)); reply_lockingX_success(blr); return True; @@ -442,7 +443,7 @@ static bool process_lockingX(struct blocking_lock_record *blr) DEBUG(10,("process_lockingX: only got %d locks of %d needed for file %s, fnum = %d. \ Waiting....\n", - blr->lock_num, num_locks, fsp->fsp_name, fsp->fnum)); + blr->lock_num, num_locks, fsp_str_dbg(fsp), fsp->fnum)); return False; } @@ -533,7 +534,7 @@ void cancel_pending_lock_requests_by_fid(files_struct *fsp, struct byte_range_lo DEBUG(10, ("remove_pending_lock_requests_by_fid - removing " "request type %d for file %s fnum = %d\n", - blr->req->cmd, fsp->fsp_name, fsp->fnum)); + blr->req->cmd, fsp_str_dbg(fsp), fsp->fnum)); blr_cancelled = blocking_lock_cancel(fsp, blr->lock_pid, @@ -583,7 +584,7 @@ void remove_pending_lock_requests_by_mid(int mid) if (br_lck) { DEBUG(10, ("remove_pending_lock_requests_by_mid - " "removing request type %d for file %s fnum " - "= %d\n", blr->req->cmd, fsp->fsp_name, + "= %d\n", blr->req->cmd, fsp_str_dbg(fsp), fsp->fnum )); brl_lock_cancel(br_lck, @@ -703,7 +704,7 @@ void process_blocking_lock_queue(void) DEBUG(5,("process_blocking_lock_queue: " "pending lock fnum = %d for file %s " "timed out.\n", blr->fsp->fnum, - blr->fsp->fsp_name )); + fsp_str_dbg(blr->fsp))); brl_lock_cancel(br_lck, blr->lock_pid, diff --git a/source3/smbd/chgpasswd.c b/source3/smbd/chgpasswd.c index 2eb09d176d..64f988f1f7 100644 --- a/source3/smbd/chgpasswd.c +++ b/source3/smbd/chgpasswd.c @@ -1024,7 +1024,7 @@ static bool check_passwd_history(struct samu *sampass, const char *plaintext) int i; uint32 pwHisLen, curr_pwHisLen; - pdb_get_account_policy(AP_PASSWORD_HISTORY, &pwHisLen); + pdb_get_account_policy(PDB_POLICY_PASSWORD_HISTORY, &pwHisLen); if (pwHisLen == 0) { return False; } @@ -1107,7 +1107,7 @@ NTSTATUS change_oem_password(struct samu *hnd, char *old_passwd, char *new_passw * denies machines to change the password. * * Should we deny also SRVTRUST and/or DOMSTRUST ? .SSS. */ if (pdb_get_acct_ctrl(hnd) & ACB_WSTRUST) { - if (pdb_get_account_policy(AP_REFUSE_MACHINE_PW_CHANGE, &refuse) && refuse) { + if (pdb_get_account_policy(PDB_POLICY_REFUSE_MACHINE_PW_CHANGE, &refuse) && refuse) { DEBUG(1, ("Machine %s cannot change password now, " "denied by Refuse Machine Password Change policy\n", username)); @@ -1130,7 +1130,7 @@ NTSTATUS change_oem_password(struct samu *hnd, char *old_passwd, char *new_passw return NT_STATUS_ACCOUNT_RESTRICTION; } - if (pdb_get_account_policy(AP_MIN_PASSWORD_LEN, &min_len) && (str_charnum(new_passwd) < min_len)) { + if (pdb_get_account_policy(PDB_POLICY_MIN_PASSWORD_LEN, &min_len) && (str_charnum(new_passwd) < min_len)) { DEBUG(1, ("user %s cannot change password - password too short\n", username)); DEBUGADD(1, (" account policy min password len = %d\n", min_len)); diff --git a/source3/smbd/close.c b/source3/smbd/close.c index a0672f3949..788b0a7cec 100644 --- a/source3/smbd/close.c +++ b/source3/smbd/close.c @@ -36,90 +36,99 @@ static NTSTATUS check_magic(struct files_struct *fsp) TALLOC_CTX *ctx = NULL; const char *p; struct connection_struct *conn = fsp->conn; + char *fname = NULL; + NTSTATUS status; if (!*lp_magicscript(SNUM(conn))) { return NT_STATUS_OK; } - DEBUG(5,("checking magic for %s\n",fsp->fsp_name)); + DEBUG(5,("checking magic for %s\n", fsp_str_dbg(fsp))); + + ctx = talloc_stackframe(); - if (!(p = strrchr_m(fsp->fsp_name,'/'))) { - p = fsp->fsp_name; + fname = fsp->fsp_name->base_name; + + if (!(p = strrchr_m(fname,'/'))) { + p = fname; } else { p++; } if (!strequal(lp_magicscript(SNUM(conn)),p)) { - return NT_STATUS_OK; + status = NT_STATUS_OK; + goto out; } - ctx = talloc_stackframe(); - if (*lp_magicoutput(SNUM(conn))) { magic_output = lp_magicoutput(SNUM(conn)); } else { magic_output = talloc_asprintf(ctx, "%s.out", - fsp->fsp_name); + fname); } if (!magic_output) { - TALLOC_FREE(ctx); - return NT_STATUS_NO_MEMORY; + status = NT_STATUS_NO_MEMORY; + goto out; } /* Ensure we don't depend on user's PATH. */ - p = talloc_asprintf(ctx, "./%s", fsp->fsp_name); + p = talloc_asprintf(ctx, "./%s", fname); if (!p) { - TALLOC_FREE(ctx); - return NT_STATUS_NO_MEMORY; + status = NT_STATUS_NO_MEMORY; + goto out; } - if (chmod(fsp->fsp_name,0755) == -1) { - TALLOC_FREE(ctx); - return map_nt_error_from_unix(errno); + if (chmod(fname, 0755) == -1) { + status = map_nt_error_from_unix(errno); + goto out; } ret = smbrun(p,&tmp_fd); DEBUG(3,("Invoking magic command %s gave %d\n", p,ret)); - unlink(fsp->fsp_name); + unlink(fname); if (ret != 0 || tmp_fd == -1) { if (tmp_fd != -1) { close(tmp_fd); } - TALLOC_FREE(ctx); - return NT_STATUS_UNSUCCESSFUL; + status = NT_STATUS_UNSUCCESSFUL; + goto out; } outfd = open(magic_output, O_CREAT|O_EXCL|O_RDWR, 0600); if (outfd == -1) { int err = errno; close(tmp_fd); - TALLOC_FREE(ctx); - return map_nt_error_from_unix(err); + status = map_nt_error_from_unix(err); + goto out; } if (sys_fstat(tmp_fd,&st) == -1) { int err = errno; close(tmp_fd); close(outfd); - TALLOC_FREE(ctx); - return map_nt_error_from_unix(err); + status = map_nt_error_from_unix(err); + goto out; } if (transfer_file(tmp_fd,outfd,(SMB_OFF_T)st.st_ex_size) == (SMB_OFF_T)-1) { int err = errno; close(tmp_fd); close(outfd); - TALLOC_FREE(ctx); - return map_nt_error_from_unix(err); + status = map_nt_error_from_unix(err); + goto out; } close(tmp_fd); if (close(outfd) == -1) { - TALLOC_FREE(ctx); - return map_nt_error_from_unix(errno); + status = map_nt_error_from_unix(errno); + goto out; } + + status = NT_STATUS_OK; + + out: TALLOC_FREE(ctx); - return NT_STATUS_OK; + return status; } /**************************************************************************** @@ -261,18 +270,10 @@ static NTSTATUS close_remove_share_mode(files_struct *fsp, bool delete_file = false; bool changed_user = false; struct share_mode_lock *lck = NULL; - struct smb_filename *smb_fname = NULL; - char *fname = NULL; NTSTATUS status = NT_STATUS_OK; int ret; struct file_id id; - status = create_synthetic_smb_fname_split(talloc_tos(), fsp->fsp_name, - NULL, &smb_fname); - if (!NT_STATUS_IS_OK(status)) { - goto done; - } - /* * Lock the share entries, and determine if we should delete * on close. If so delete whilst the lock is still in effect. @@ -284,7 +285,7 @@ static NTSTATUS close_remove_share_mode(files_struct *fsp, if (lck == NULL) { DEBUG(0, ("close_remove_share_mode: Could not get share mode " - "lock for file %s\n", smb_fname_str_dbg(smb_fname))); + "lock for file %s\n", fsp_str_dbg(fsp))); status = NT_STATUS_INVALID_PARAMETER; goto done; } @@ -296,7 +297,7 @@ static NTSTATUS close_remove_share_mode(files_struct *fsp, if (!del_share_mode(lck, fsp)) { DEBUG(0, ("close_remove_share_mode: Could not delete share " "entry for file %s\n", - smb_fname_str_dbg(smb_fname))); + fsp_str_dbg(fsp))); } if (fsp->initial_delete_on_close && (lck->delete_token == NULL)) { @@ -354,7 +355,7 @@ static NTSTATUS close_remove_share_mode(files_struct *fsp, */ DEBUG(5,("close_remove_share_mode: file %s. Delete on close was set " - "- deleting file.\n", smb_fname_str_dbg(smb_fname))); + "- deleting file.\n", fsp_str_dbg(fsp))); /* * Don't try to update the write time when we delete the file @@ -366,7 +367,7 @@ static NTSTATUS close_remove_share_mode(files_struct *fsp, DEBUG(5,("close_remove_share_mode: file %s. " "Change user to uid %u\n", - smb_fname_str_dbg(smb_fname), + fsp_str_dbg(fsp), (unsigned int)lck->delete_token->uid)); if (!push_sec_ctx()) { @@ -387,30 +388,30 @@ static NTSTATUS close_remove_share_mode(files_struct *fsp, hasn't been renamed. */ if (fsp->posix_open) { - ret = SMB_VFS_LSTAT(conn, smb_fname); + ret = SMB_VFS_LSTAT(conn, fsp->fsp_name); } else { - ret = SMB_VFS_STAT(conn, smb_fname); + ret = SMB_VFS_STAT(conn, fsp->fsp_name); } if (ret != 0) { DEBUG(5,("close_remove_share_mode: file %s. Delete on close " "was set and stat failed with error %s\n", - smb_fname_str_dbg(smb_fname), strerror(errno))); + fsp_str_dbg(fsp), strerror(errno))); /* * Don't save the errno here, we ignore this error */ goto done; } - id = vfs_file_id_from_sbuf(conn, &smb_fname->st); + id = vfs_file_id_from_sbuf(conn, &fsp->fsp_name->st); if (!file_id_equal(&fsp->file_id, &id)) { DEBUG(5,("close_remove_share_mode: file %s. Delete on close " "was set and dev and/or inode does not match\n", - smb_fname_str_dbg(smb_fname))); + fsp_str_dbg(fsp))); DEBUG(5,("close_remove_share_mode: file %s. stored file_id %s, " "stat file_id %s\n", - smb_fname_str_dbg(smb_fname), + fsp_str_dbg(fsp), file_id_string_tos(&fsp->file_id), file_id_string_tos(&id))); /* @@ -420,9 +421,9 @@ static NTSTATUS close_remove_share_mode(files_struct *fsp, } if ((conn->fs_capabilities & FILE_NAMED_STREAMS) - && !is_ntfs_stream_smb_fname(smb_fname)) { + && !is_ntfs_stream_smb_fname(fsp->fsp_name)) { - status = delete_all_streams(conn, smb_fname->base_name); + status = delete_all_streams(conn, fsp->fsp_name->base_name); if (!NT_STATUS_IS_OK(status)) { DEBUG(5, ("delete_all_streams failed: %s\n", @@ -432,7 +433,7 @@ static NTSTATUS close_remove_share_mode(files_struct *fsp, } - if (SMB_VFS_UNLINK(conn, smb_fname) != 0) { + if (SMB_VFS_UNLINK(conn, fsp->fsp_name) != 0) { /* * This call can potentially fail as another smbd may * have had the file open with delete on close set and @@ -443,21 +444,14 @@ static NTSTATUS close_remove_share_mode(files_struct *fsp, DEBUG(5,("close_remove_share_mode: file %s. Delete on close " "was set and unlink failed with error %s\n", - smb_fname_str_dbg(smb_fname), strerror(errno))); + fsp_str_dbg(fsp), strerror(errno))); status = map_nt_error_from_unix(errno); } - status = get_full_smb_filename(talloc_tos(), smb_fname, &fname); - if (!NT_STATUS_IS_OK(status)) { - goto done; - } - notify_fname(conn, NOTIFY_ACTION_REMOVED, FILE_NOTIFY_CHANGE_FILE_NAME, - fname); - - TALLOC_FREE(fname); + fsp->fsp_name->base_name); /* As we now have POSIX opens which can unlink * with other open files we may have taken @@ -476,7 +470,6 @@ static NTSTATUS close_remove_share_mode(files_struct *fsp, } TALLOC_FREE(lck); - TALLOC_FREE(smb_fname); return status; } @@ -499,7 +492,6 @@ void set_close_write_time(struct files_struct *fsp, struct timespec ts) static NTSTATUS update_write_time_on_close(struct files_struct *fsp) { - struct smb_filename *smb_fname = NULL; struct smb_file_time ft; NTSTATUS status; int ret = -1; @@ -514,43 +506,32 @@ static NTSTATUS update_write_time_on_close(struct files_struct *fsp) fsp->close_write_time = timespec_current(); } - /* XXX: Remove when fsp->fsp_name is converted to smb_filename. */ - status = create_synthetic_smb_fname_split(talloc_tos(), fsp->fsp_name, - NULL, &smb_fname); - if (!NT_STATUS_IS_OK(status)) { - goto out; - } - /* Ensure we have a valid stat struct for the source. */ if (fsp->fh->fd != -1) { - ret = SMB_VFS_FSTAT(fsp, &smb_fname->st); + ret = SMB_VFS_FSTAT(fsp, &fsp->fsp_name->st); } else { if (fsp->posix_open) { - ret = SMB_VFS_LSTAT(fsp->conn, smb_fname); + ret = SMB_VFS_LSTAT(fsp->conn, fsp->fsp_name); } else { - ret = SMB_VFS_STAT(fsp->conn, smb_fname); + ret = SMB_VFS_STAT(fsp->conn, fsp->fsp_name); } } if (ret == -1) { - status = map_nt_error_from_unix(errno); - goto out; + return map_nt_error_from_unix(errno); } - if (!VALID_STAT(smb_fname->st)) { + if (!VALID_STAT(fsp->fsp_name->st)) { /* if it doesn't seem to be a real file */ - status = NT_STATUS_OK; - goto out; + return NT_STATUS_OK; } ft.mtime = fsp->close_write_time; - status = smb_set_file_time(fsp->conn, fsp, smb_fname, &ft, true); + status = smb_set_file_time(fsp->conn, fsp, fsp->fsp_name, &ft, true); if (!NT_STATUS_IS_OK(status)) { - goto out; + return status; } - out: - TALLOC_FREE(smb_fname); return status; } @@ -647,7 +628,7 @@ static NTSTATUS close_normal_file(struct smb_request *req, files_struct *fsp, status = ntstatus_keeperror(status, tmp); DEBUG(2,("%s closed file %s (numopen=%d) %s\n", - conn->server_info->unix_name,fsp->fsp_name, + conn->server_info->unix_name, fsp_str_dbg(fsp), conn->num_files_open - 1, nt_errstr(status) )); @@ -663,16 +644,9 @@ static NTSTATUS close_directory(struct smb_request *req, files_struct *fsp, enum file_close_type close_type) { struct share_mode_lock *lck = NULL; - struct smb_filename *smb_dname = NULL; bool delete_dir = False; NTSTATUS status = NT_STATUS_OK; - status = create_synthetic_smb_fname_split(talloc_tos(), fsp->fsp_name, - NULL, &smb_dname); - if (!NT_STATUS_IS_OK(status)) { - goto out; - } - /* * NT can set delete_on_close of the last open * reference to a directory also. @@ -683,14 +657,14 @@ static NTSTATUS close_directory(struct smb_request *req, files_struct *fsp, if (lck == NULL) { DEBUG(0, ("close_directory: Could not get share mode lock for " - "%s\n", smb_fname_str_dbg(smb_dname))); + "%s\n", fsp_str_dbg(fsp))); status = NT_STATUS_INVALID_PARAMETER; goto out; } if (!del_share_mode(lck, fsp)) { DEBUG(0, ("close_directory: Could not delete share entry for " - "%s\n", smb_fname_str_dbg(smb_dname))); + "%s\n", fsp_str_dbg(fsp))); } if (fsp->initial_delete_on_close) { @@ -704,7 +678,7 @@ static NTSTATUS close_directory(struct smb_request *req, files_struct *fsp, become_user(fsp->conn, fsp->vuid); became_user = True; } - send_stat_cache_delete_message(fsp->fsp_name); + send_stat_cache_delete_message(fsp->fsp_name->base_name); set_delete_on_close_lck(lck, True, ¤t_user.ut); if (became_user) { unbecome_user(); @@ -747,11 +721,12 @@ static NTSTATUS close_directory(struct smb_request *req, files_struct *fsp, TALLOC_FREE(lck); - status = rmdir_internals(talloc_tos(), fsp->conn, smb_dname); + status = rmdir_internals(talloc_tos(), fsp->conn, + fsp->fsp_name); DEBUG(5,("close_directory: %s. Delete on close was set - " "deleting directory returned %s.\n", - smb_fname_str_dbg(smb_dname), nt_errstr(status))); + fsp_str_dbg(fsp), nt_errstr(status))); /* unbecome user. */ pop_sec_ctx(); @@ -774,7 +749,7 @@ static NTSTATUS close_directory(struct smb_request *req, files_struct *fsp, if (!NT_STATUS_IS_OK(status)) { DEBUG(0, ("Could not close dir! fname=%s, fd=%d, err=%d=%s\n", - smb_fname_str_dbg(smb_dname), fsp->fh->fd, errno, + fsp_str_dbg(fsp), fsp->fh->fd, errno, strerror(errno))); } @@ -786,7 +761,6 @@ static NTSTATUS close_directory(struct smb_request *req, files_struct *fsp, out: TALLOC_FREE(lck); - TALLOC_FREE(smb_dname); return status; } diff --git a/source3/smbd/dosmode.c b/source3/smbd/dosmode.c index ca926aa33c..bd0c7df959 100644 --- a/source3/smbd/dosmode.c +++ b/source3/smbd/dosmode.c @@ -448,8 +448,8 @@ static bool get_stat_dos_flags(connection_struct *conn, if (S_ISDIR(smb_fname->st.st_ex_mode)) *dosmode |= aDIR; - *dosmode |= set_sparse_flag(smb_fname->st); - *dosmode |= set_link_read_only_flag(smb_fname->st); + *dosmode |= set_sparse_flag(&smb_fname->st); + *dosmode |= set_link_read_only_flag(&smb_fname->st); return true; } @@ -845,7 +845,7 @@ bool update_write_time(struct files_struct *fsp) } notify_fname(fsp->conn, NOTIFY_ACTION_MODIFIED, - FILE_NOTIFY_CHANGE_LAST_WRITE, fsp->fsp_name); + FILE_NOTIFY_CHANGE_LAST_WRITE, fsp->fsp_name->base_name); return true; } diff --git a/source3/smbd/error.c b/source3/smbd/error.c index ce22f86414..874efa2a0b 100644 --- a/source3/smbd/error.c +++ b/source3/smbd/error.c @@ -136,33 +136,3 @@ void reply_openerror(struct smb_request *req, NTSTATUS status) reply_nterror(req, status); } } - -void reply_unix_error(struct smb_request *req, uint8 defclass, uint32 defcode, - NTSTATUS defstatus, int line, const char *file) -{ - int eclass=defclass; - int ecode=defcode; - NTSTATUS ntstatus = defstatus; - int i=0; - - TALLOC_FREE(req->outbuf); - reply_outbuf(req, 0, 0); - - if (errno != 0) { - DEBUG(3,("unix_error_packet: error string = %s\n", - strerror(errno))); - - while (unix_dos_nt_errmap[i].dos_class != 0) { - if (unix_dos_nt_errmap[i].unix_error == errno) { - eclass = unix_dos_nt_errmap[i].dos_class; - ecode = unix_dos_nt_errmap[i].dos_code; - ntstatus = unix_dos_nt_errmap[i].nt_error; - break; - } - i++; - } - } - - error_packet_set((char *)req->outbuf, eclass, ecode, ntstatus, - line, file); -} diff --git a/source3/smbd/fake_file.c b/source3/smbd/fake_file.c index ef54398bc4..743d88f360 100644 --- a/source3/smbd/fake_file.c +++ b/source3/smbd/fake_file.c @@ -71,23 +71,32 @@ static struct fake_file_handle *init_fake_file_handle(enum FAKE_FILE_TYPE type) Does this name match a fake filename ? ****************************************************************************/ -enum FAKE_FILE_TYPE is_fake_file(const char *fname) +enum FAKE_FILE_TYPE is_fake_file(const struct smb_filename *smb_fname) { #ifdef HAVE_SYS_QUOTAS int i; + char *fname = NULL; + NTSTATUS status; #endif - if (!fname) { + if (!smb_fname) { return FAKE_FILE_TYPE_NONE; } #ifdef HAVE_SYS_QUOTAS + status = get_full_smb_filename(talloc_tos(), smb_fname, &fname); + if (!NT_STATUS_IS_OK(status)) { + return FAKE_FILE_TYPE_NONE; + } + for (i=0;fake_files[i].name!=NULL;i++) { if (strncmp(fname,fake_files[i].name,strlen(fake_files[i].name))==0) { DEBUG(5,("is_fake_file: [%s] is a fake file\n",fname)); + TALLOC_FREE(fname); return fake_files[i].type; } } + TALLOC_FREE(fname); #endif return FAKE_FILE_TYPE_NONE; @@ -101,7 +110,7 @@ enum FAKE_FILE_TYPE is_fake_file(const char *fname) NTSTATUS open_fake_file(struct smb_request *req, connection_struct *conn, uint16_t current_vuid, enum FAKE_FILE_TYPE fake_file_type, - const char *fname, + const struct smb_filename *smb_fname, uint32 access_mask, files_struct **result) { @@ -112,7 +121,8 @@ NTSTATUS open_fake_file(struct smb_request *req, connection_struct *conn, if (conn->server_info->utok.uid != 0) { DEBUG(3, ("open_fake_file_shared: access_denied to " "service[%s] file[%s] user[%s]\n", - lp_servicename(SNUM(conn)), fname, + lp_servicename(SNUM(conn)), + smb_fname_str_dbg(smb_fname), conn->server_info->unix_name)); return NT_STATUS_ACCESS_DENIED; @@ -124,7 +134,8 @@ NTSTATUS open_fake_file(struct smb_request *req, connection_struct *conn, } DEBUG(5,("open_fake_file_shared: fname = %s, FID = %d, access_mask = 0x%x\n", - fname, fsp->fnum, (unsigned int)access_mask)); + smb_fname_str_dbg(smb_fname), fsp->fnum, + (unsigned int)access_mask)); fsp->conn = conn; fsp->fh->fd = -1; @@ -132,8 +143,12 @@ NTSTATUS open_fake_file(struct smb_request *req, connection_struct *conn, fsp->fh->pos = -1; fsp->can_lock = False; /* Should this be true ? - No, JRA */ fsp->access_mask = access_mask; - string_set(&fsp->fsp_name,fname); - + status = fsp_set_smb_fname(fsp, smb_fname); + if (!NT_STATUS_IS_OK(status)) { + file_free(req, fsp); + return NT_STATUS_NO_MEMORY; + } + fsp->fake_file_handle = init_fake_file_handle(fake_file_type); if (fsp->fake_file_handle==NULL) { diff --git a/source3/smbd/file_access.c b/source3/smbd/file_access.c index d8fee1db06..7d0a552956 100644 --- a/source3/smbd/file_access.c +++ b/source3/smbd/file_access.c @@ -33,7 +33,6 @@ bool can_access_file_acl(struct connection_struct *conn, NTSTATUS status; uint32_t access_granted; struct security_descriptor *secdesc = NULL; - char *fname = NULL; bool ret; if (conn->server_info->utok.uid == 0 || conn->admin_user) { @@ -41,13 +40,7 @@ bool can_access_file_acl(struct connection_struct *conn, return true; } - status = get_full_smb_filename(talloc_tos(), smb_fname, &fname); - if (!NT_STATUS_IS_OK(status)) { - ret = false; - goto out; - } - - status = SMB_VFS_GET_NT_ACL(conn, fname, + status = SMB_VFS_GET_NT_ACL(conn, smb_fname->base_name, (OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION), @@ -62,7 +55,6 @@ bool can_access_file_acl(struct connection_struct *conn, access_mask, &access_granted); ret = NT_STATUS_IS_OK(status); out: - TALLOC_FREE(fname); TALLOC_FREE(secdesc); return ret; } diff --git a/source3/smbd/fileio.c b/source3/smbd/fileio.c index 0c13b845df..bd609d3e86 100644 --- a/source3/smbd/fileio.c +++ b/source3/smbd/fileio.c @@ -57,6 +57,7 @@ ssize_t read_file(files_struct *fsp,char *data,SMB_OFF_T pos,size_t n) /* you can't read from print files */ if (fsp->print_file) { + errno = EBADF; return -1; } @@ -102,7 +103,7 @@ tryagain: } DEBUG(10,("read_file (%s): pos = %.0f, size = %lu, returned %lu\n", - fsp->fsp_name, (double)pos, (unsigned long)n, (long)ret )); + fsp_str_dbg(fsp), (double)pos, (unsigned long)n, (long)ret)); fsp->fh->pos += ret; fsp->fh->position_information = fsp->fh->pos; @@ -135,7 +136,7 @@ static ssize_t real_write_file(struct smb_request *req, } DEBUG(10,("real_write_file (%s): pos = %.0f, size = %lu, returned %ld\n", - fsp->fsp_name, (double)pos, (unsigned long)n, (long)ret )); + fsp_str_dbg(fsp), (double)pos, (unsigned long)n, (long)ret)); if (ret != -1) { fsp->fh->pos += ret; @@ -163,8 +164,9 @@ static int wcp_file_size_change(files_struct *fsp) wcp->file_size = wcp->offset + wcp->data_size; ret = SMB_VFS_FTRUNCATE(fsp, wcp->file_size); if (ret == -1) { - DEBUG(0,("wcp_file_size_change (%s): ftruncate of size %.0f error %s\n", - fsp->fsp_name, (double)wcp->file_size, strerror(errno) )); + DEBUG(0,("wcp_file_size_change (%s): ftruncate of size %.0f " + "error %s\n", fsp_str_dbg(fsp), + (double)wcp->file_size, strerror(errno))); } return ret; } @@ -178,7 +180,7 @@ static void update_write_time_handler(struct event_context *ctx, /* Remove the timed event handler. */ TALLOC_FREE(fsp->update_write_time_event); - DEBUG(5, ("Update write time on %s\n", fsp->fsp_name)); + DEBUG(5, ("Update write time on %s\n", fsp_str_dbg(fsp))); /* change the write time if not already changed by someone else */ update_write_time(fsp); @@ -243,7 +245,8 @@ void trigger_write_time_update_immediate(struct files_struct *fsp) } TALLOC_FREE(fsp->update_write_time_event); - DEBUG(5, ("Update write time immediate on %s\n", fsp->fsp_name)); + DEBUG(5, ("Update write time immediate on %s\n", + fsp_str_dbg(fsp))); fsp->update_write_time_triggered = true; @@ -284,28 +287,17 @@ ssize_t write_file(struct smb_request *req, } if (!fsp->modified) { - struct smb_filename *smb_fname = NULL; - NTSTATUS status; - fsp->modified = True; - status = create_synthetic_smb_fname_split(talloc_tos(), - fsp->fsp_name, NULL, - &smb_fname); - if (!NT_STATUS_IS_OK(status)) { - errno = map_errno_from_nt_status(status); - return -1; - } - - if (SMB_VFS_FSTAT(fsp, &smb_fname->st) == 0) { + if (SMB_VFS_FSTAT(fsp, &fsp->fsp_name->st) == 0) { int dosmode; trigger_write_time_update(fsp); - dosmode = dos_mode(fsp->conn, smb_fname); + dosmode = dos_mode(fsp->conn, fsp->fsp_name); if ((lp_store_dos_attributes(SNUM(fsp->conn)) || MAP_ARCHIVE(fsp->conn)) && !IS_DOS_ARCHIVE(dosmode)) { - file_set_dosmode(fsp->conn, smb_fname, - dosmode | aARCH, NULL, false); + file_set_dosmode(fsp->conn, fsp->fsp_name, + dosmode | aARCH, NULL, false); } /* @@ -315,11 +307,10 @@ ssize_t write_file(struct smb_request *req, if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type) && !wcp) { setup_write_cache(fsp, - smb_fname->st.st_ex_size); + fsp->fsp_name->st.st_ex_size); wcp = fsp->wcp; } } - TALLOC_FREE(smb_fname); } #ifdef WITH_PROFILE @@ -381,8 +372,10 @@ nonop=%u allocated=%u active=%u direct=%u perfect=%u readhits=%u\n", return total_written; } - DEBUG(9,("write_file (%s)(fd=%d pos=%.0f size=%u) wcp->offset=%.0f wcp->data_size=%u\n", - fsp->fsp_name, fsp->fh->fd, (double)pos, (unsigned int)n, (double)wcp->offset, (unsigned int)wcp->data_size)); + DEBUG(9,("write_file (%s)(fd=%d pos=%.0f size=%u) wcp->offset=%.0f " + "wcp->data_size=%u\n", fsp_str_dbg(fsp), fsp->fh->fd, + (double)pos, (unsigned int)n, (double)wcp->offset, + (unsigned int)wcp->data_size)); fsp->fh->pos = pos + n; @@ -827,7 +820,8 @@ void delete_write_cache(files_struct *fsp) SAFE_FREE(wcp->data); SAFE_FREE(fsp->wcp); - DEBUG(10,("delete_write_cache: File %s deleted write cache\n", fsp->fsp_name )); + DEBUG(10,("delete_write_cache: File %s deleted write cache\n", + fsp_str_dbg(fsp))); } /**************************************************************************** @@ -870,7 +864,7 @@ static bool setup_write_cache(files_struct *fsp, SMB_OFF_T file_size) allocated_write_caches++; DEBUG(10,("setup_write_cache: File %s allocated write cache size %lu\n", - fsp->fsp_name, (unsigned long)wcp->alloc_size )); + fsp_str_dbg(fsp), (unsigned long)wcp->alloc_size)); return True; } @@ -887,7 +881,7 @@ void set_filelen_write_cache(files_struct *fsp, SMB_OFF_T file_size) char *msg; if (asprintf(&msg, "set_filelen_write_cache: size change " "on file %s with write cache size = %lu\n", - fsp->fsp_name, + fsp->fsp_name->base_name, (unsigned long)fsp->wcp->data_size) != -1) { smb_panic(msg); } else { @@ -969,7 +963,13 @@ NTSTATUS sync_file(connection_struct *conn, files_struct *fsp, bool write_throug int fsp_stat(files_struct *fsp, SMB_STRUCT_STAT *pst) { if (fsp->fh->fd == -1) { - return vfs_stat_smb_fname(fsp->conn, fsp->fsp_name, pst); + int ret; + + ret = SMB_VFS_STAT(fsp->conn, fsp->fsp_name); + if (ret != -1) { + *pst = fsp->fsp_name->st; + } + return ret; } else { return SMB_VFS_FSTAT(fsp, pst); } diff --git a/source3/smbd/filename.c b/source3/smbd/filename.c index 29ebc37d1a..09f9a418bd 100644 --- a/source3/smbd/filename.c +++ b/source3/smbd/filename.c @@ -80,201 +80,6 @@ static NTSTATUS determine_path_error(const char *name, } } -/** - * XXX: This is temporary and there should be no callers of this outside of - * this file once smb_filename is plumbed through all path based operations. - * The one legitimate caller currently is smb_fname_str_dbg(), which this - * could be made static for. - */ -NTSTATUS get_full_smb_filename(TALLOC_CTX *ctx, const struct smb_filename *smb_fname, - char **full_name) -{ - if (smb_fname->stream_name) { - *full_name = talloc_asprintf(ctx, "%s%s", smb_fname->base_name, - smb_fname->stream_name); - } else { - *full_name = talloc_strdup(ctx, smb_fname->base_name); - } - - if (!*full_name) { - return NT_STATUS_NO_MEMORY; - } - - return NT_STATUS_OK; -} - -/** - * There are actually legitimate callers of this such as functions that - * enumerate streams using the SMB_VFS_STREAMINFO interface and then want to - * operate on each stream. - */ -NTSTATUS create_synthetic_smb_fname(TALLOC_CTX *ctx, const char *base_name, - const char *stream_name, - const SMB_STRUCT_STAT *psbuf, - struct smb_filename **smb_fname_out) -{ - struct smb_filename smb_fname_loc; - - ZERO_STRUCT(smb_fname_loc); - - /* Setup the base_name/stream_name. */ - smb_fname_loc.base_name = CONST_DISCARD(char *, base_name); - smb_fname_loc.stream_name = CONST_DISCARD(char *, stream_name); - - /* Copy the psbuf if one was given. */ - if (psbuf) - smb_fname_loc.st = *psbuf; - - /* Let copy_smb_filename() do the heavy lifting. */ - return copy_smb_filename(ctx, &smb_fname_loc, smb_fname_out); -} - -/** - * XXX: This is temporary and there should be no callers of this once - * smb_filename is plumbed through all path based operations. - */ -NTSTATUS create_synthetic_smb_fname_split(TALLOC_CTX *ctx, - const char *fname, - const SMB_STRUCT_STAT *psbuf, - struct smb_filename **smb_fname_out) -{ - NTSTATUS status; - const char *stream_name = NULL; - char *base_name = NULL; - - if (!lp_posix_pathnames()) { - stream_name = strchr_m(fname, ':'); - } - - /* Setup the base_name/stream_name. */ - if (stream_name) { - base_name = talloc_strndup(ctx, fname, - PTR_DIFF(stream_name, fname)); - } else { - base_name = talloc_strdup(ctx, fname); - } - - if (!base_name) { - return NT_STATUS_NO_MEMORY; - } - - status = create_synthetic_smb_fname(ctx, base_name, stream_name, psbuf, - smb_fname_out); - TALLOC_FREE(base_name); - return status; -} - -/** - * XXX: This is temporary and there should be no callers of this once - * smb_filename is plumbed through all path based operations. - */ -int vfs_stat_smb_fname(struct connection_struct *conn, const char *fname, - SMB_STRUCT_STAT *psbuf) -{ - struct smb_filename *smb_fname = NULL; - NTSTATUS status; - int ret; - - status = create_synthetic_smb_fname_split(talloc_tos(), fname, NULL, - &smb_fname); - if (!NT_STATUS_IS_OK(status)) { - errno = map_errno_from_nt_status(status); - return -1; - } - - ret = SMB_VFS_STAT(conn, smb_fname); - if (ret != -1) { - *psbuf = smb_fname->st; - } - - TALLOC_FREE(smb_fname); - return ret; -} - -/** - * XXX: This is temporary and there should be no callers of this once - * smb_filename is plumbed through all path based operations. - */ -int vfs_lstat_smb_fname(struct connection_struct *conn, const char *fname, - SMB_STRUCT_STAT *psbuf) -{ - struct smb_filename *smb_fname = NULL; - NTSTATUS status; - int ret; - - status = create_synthetic_smb_fname_split(talloc_tos(), fname, NULL, - &smb_fname); - if (!NT_STATUS_IS_OK(status)) { - errno = map_errno_from_nt_status(status); - return -1; - } - - ret = SMB_VFS_LSTAT(conn, smb_fname); - if (ret != -1) { - *psbuf = smb_fname->st; - } - - TALLOC_FREE(smb_fname); - return ret; -} - -/** - * Return a string using the debug_ctx() - */ -const char *smb_fname_str_dbg(const struct smb_filename *smb_fname) -{ - char *fname = NULL; - NTSTATUS status; - - if (smb_fname == NULL) { - return ""; - } - status = get_full_smb_filename(debug_ctx(), smb_fname, &fname); - if (!NT_STATUS_IS_OK(status)) { - return ""; - } - return fname; -} - -NTSTATUS copy_smb_filename(TALLOC_CTX *ctx, - const struct smb_filename *smb_fname_in, - struct smb_filename **smb_fname_out) -{ - - *smb_fname_out = talloc_zero(ctx, struct smb_filename); - if (*smb_fname_out == NULL) { - return NT_STATUS_NO_MEMORY; - } - - if (smb_fname_in->base_name) { - (*smb_fname_out)->base_name = - talloc_strdup(*smb_fname_out, smb_fname_in->base_name); - if (!(*smb_fname_out)->base_name) - goto no_mem_err; - } - - if (smb_fname_in->stream_name) { - (*smb_fname_out)->stream_name = - talloc_strdup(*smb_fname_out, smb_fname_in->stream_name); - if (!(*smb_fname_out)->stream_name) - goto no_mem_err; - } - - if (smb_fname_in->original_lcomp) { - (*smb_fname_out)->original_lcomp = - talloc_strdup(*smb_fname_out, smb_fname_in->original_lcomp); - if (!(*smb_fname_out)->original_lcomp) - goto no_mem_err; - } - - (*smb_fname_out)->st = smb_fname_in->st; - return NT_STATUS_OK; - - no_mem_err: - TALLOC_FREE(*smb_fname_out); - return NT_STATUS_NO_MEMORY; -} - /**************************************************************************** This routine is called to convert names from the dos namespace to unix namespace. It needs to handle any case conversions, mangling, format changes, @@ -312,23 +117,21 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx, struct smb_filename **smb_fname_out, uint32_t ucf_flags) { - SMB_STRUCT_STAT st; struct smb_filename *smb_fname = NULL; char *start, *end; char *dirpath = NULL; - char *name = NULL; char *stream = NULL; bool component_was_mangled = False; bool name_has_wildcard = False; bool posix_pathnames = false; bool allow_wcard_last_component = ucf_flags & UCF_ALLOW_WCARD_LCOMP; bool save_last_component = ucf_flags & UCF_SAVE_LCOMP; - NTSTATUS result; + NTSTATUS status; int ret = -1; *smb_fname_out = NULL; - smb_fname = talloc_zero(talloc_tos(), struct smb_filename); + smb_fname = talloc_zero(ctx, struct smb_filename); if (smb_fname == NULL) { return NT_STATUS_NO_MEMORY; } @@ -338,10 +141,10 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx, filename - so don't convert them */ if (!(smb_fname->base_name = talloc_strdup(smb_fname, orig_path))) { - return NT_STATUS_NO_MEMORY; + status = NT_STATUS_NO_MEMORY; + goto err; } - *smb_fname_out = smb_fname; - return NT_STATUS_OK; + goto done; } DEBUG(5, ("unix_convert called on file \"%s\"\n", orig_path)); @@ -369,15 +172,16 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx, */ if (!*orig_path) { - if (!(name = talloc_strdup(ctx,"."))) { - return NT_STATUS_NO_MEMORY; + if (!(smb_fname->base_name = talloc_strdup(smb_fname, "."))) { + status = NT_STATUS_NO_MEMORY; + goto err; } - if (vfs_stat_smb_fname(conn,name,&st) == 0) { - smb_fname->st = st; - } else { - return map_nt_error_from_unix(errno); + if (SMB_VFS_STAT(conn, smb_fname) != 0) { + status = map_nt_error_from_unix(errno); + goto err; } - DEBUG(5,("conversion finished \"\" -> %s\n",name)); + DEBUG(5, ("conversion finished \"\" -> %s\n", + smb_fname->base_name)); goto done; } @@ -385,17 +189,19 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx, orig_path[1] == '\0')) { /* Start of pathname can't be "." only. */ if (orig_path[1] == '\0' || orig_path[2] == '\0') { - result = NT_STATUS_OBJECT_NAME_INVALID; + status = NT_STATUS_OBJECT_NAME_INVALID; } else { - result =determine_path_error( - &orig_path[2], allow_wcard_last_component); + status =determine_path_error(&orig_path[2], + allow_wcard_last_component); } - return result; + goto err; } - if (!(name = talloc_strdup(ctx, orig_path))) { + /* Start with the full orig_path as given by the caller. */ + if (!(smb_fname->base_name = talloc_strdup(smb_fname, orig_path))) { DEBUG(0, ("talloc_strdup failed\n")); - return NT_STATUS_NO_MEMORY; + status = NT_STATUS_NO_MEMORY; + goto err; } /* @@ -409,7 +215,7 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx, if (conn->case_sensitive && !conn->case_preserve && !conn->short_case_preserve) { - strnorm(name, lp_defaultcase(SNUM(conn))); + strnorm(smb_fname->base_name, lp_defaultcase(SNUM(conn))); } /* @@ -417,44 +223,60 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx, */ if(save_last_component) { - end = strrchr_m(name, '/'); + end = strrchr_m(smb_fname->base_name, '/'); if (end) { - smb_fname->original_lcomp = talloc_strdup(ctx, + smb_fname->original_lcomp = talloc_strdup(smb_fname, end + 1); } else { - smb_fname->original_lcomp = talloc_strdup(ctx, name); + smb_fname->original_lcomp = + talloc_strdup(smb_fname, smb_fname->base_name); + } + if (smb_fname->original_lcomp == NULL) { + status = NT_STATUS_NO_MEMORY; + goto err; } } posix_pathnames = lp_posix_pathnames(); - /* Strip off the stream. Should we use any of the other stream parsing - * at this point? Also, should we set the is_stream bit? */ + /* + * Strip off the stream, and add it back when we're done with the + * base_name. + */ if (!posix_pathnames) { - stream = strchr_m(name, ':'); + stream = strchr_m(smb_fname->base_name, ':'); if (stream != NULL) { - char *tmp = talloc_strdup(ctx, stream); + char *tmp = talloc_strdup(smb_fname, stream); if (tmp == NULL) { - TALLOC_FREE(name); - return NT_STATUS_NO_MEMORY; + status = NT_STATUS_NO_MEMORY; + goto err; } + /* + * Since this is actually pointing into + * smb_fname->base_name this truncates base_name. + */ *stream = '\0'; stream = tmp; } } - start = name; + start = smb_fname->base_name; - /* If we're providing case insentive semantics or + /* + * If we're providing case insentive semantics or * the underlying filesystem is case insensitive, * then a case-normalized hit in the stat-cache is * authoratitive. JRA. + * + * Note: We're only checking base_name. The stream_name will be + * added and verified in build_stream_path(). */ - if((!conn->case_sensitive || !(conn->fs_capabilities & FILE_CASE_SENSITIVE_SEARCH)) && - stat_cache_lookup(conn, &name, &dirpath, &start, &st)) { - smb_fname->st = st; + if((!conn->case_sensitive || !(conn->fs_capabilities & + FILE_CASE_SENSITIVE_SEARCH)) && + stat_cache_lookup(conn, &smb_fname->base_name, &dirpath, &start, + &smb_fname->st)) { goto done; } @@ -465,43 +287,46 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx, if ((dirpath == NULL) && (!(dirpath = talloc_strdup(ctx,"")))) { DEBUG(0, ("talloc_strdup failed\n")); - TALLOC_FREE(name); - return NT_STATUS_NO_MEMORY; + status = NT_STATUS_NO_MEMORY; + goto err; } /* - * stat the name - if it exists then we are all done! + * stat the name - if it exists then we can add the stream back (if + * there was one) and be done! */ if (posix_pathnames) { - ret = vfs_lstat_smb_fname(conn,name,&st); + ret = SMB_VFS_LSTAT(conn, smb_fname); } else { - ret = vfs_stat_smb_fname(conn,name,&st); + ret = SMB_VFS_STAT(conn, smb_fname); } if (ret == 0) { /* Ensure we catch all names with in "/." this is disallowed under Windows. */ - const char *p = strstr(name, "/."); /* mb safe. */ + const char *p = strstr(smb_fname->base_name, "/."); /*mb safe*/ if (p) { if (p[2] == '/') { /* Error code within a pathname. */ - result = NT_STATUS_OBJECT_PATH_NOT_FOUND; + status = NT_STATUS_OBJECT_PATH_NOT_FOUND; goto fail; } else if (p[2] == '\0') { /* Error code at the end of a pathname. */ - result = NT_STATUS_OBJECT_NAME_INVALID; + status = NT_STATUS_OBJECT_NAME_INVALID; goto fail; } } - stat_cache_add(orig_path, name, conn->case_sensitive); - DEBUG(5,("conversion finished %s -> %s\n",orig_path, name)); - smb_fname->st = st; + /* Add the path (not including the stream) to the cache. */ + stat_cache_add(orig_path, smb_fname->base_name, + conn->case_sensitive); + DEBUG(5,("conversion of base_name finished %s -> %s\n", + orig_path, smb_fname->base_name)); goto done; } DEBUG(5,("unix_convert begin: name = %s, dirpath = %s, start = %s\n", - name, dirpath, start)); + smb_fname->base_name, dirpath, start)); /* * A special case - if we don't have any mangling chars and are case @@ -509,8 +334,9 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx, * won't help. */ - if ((conn->case_sensitive || !(conn->fs_capabilities & FILE_CASE_SENSITIVE_SEARCH)) && - !mangle_is_mangled(name, conn->params)) { + if ((conn->case_sensitive || !(conn->fs_capabilities & + FILE_CASE_SENSITIVE_SEARCH)) && + !mangle_is_mangled(smb_fname->base_name, conn->params)) { goto done; } @@ -549,11 +375,12 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx, if (save_last_component) { TALLOC_FREE(smb_fname->original_lcomp); - smb_fname->original_lcomp = talloc_strdup(ctx, + smb_fname->original_lcomp = talloc_strdup(smb_fname, end ? end + 1 : start); if (!smb_fname->original_lcomp) { DEBUG(0, ("talloc failed\n")); - return NT_STATUS_NO_MEMORY; + status = NT_STATUS_NO_MEMORY; + goto err; } } @@ -562,9 +389,9 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx, if (ISDOT(start)) { if (!end) { /* Error code at the end of a pathname. */ - result = NT_STATUS_OBJECT_NAME_INVALID; + status = NT_STATUS_OBJECT_NAME_INVALID; } else { - result = determine_path_error(end+1, + status = determine_path_error(end+1, allow_wcard_last_component); } goto fail; @@ -577,13 +404,13 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx, /* Wildcard not valid anywhere. */ if (name_has_wildcard && !allow_wcard_last_component) { - result = NT_STATUS_OBJECT_NAME_INVALID; + status = NT_STATUS_OBJECT_NAME_INVALID; goto fail; } /* Wildcards never valid within a pathname. */ if (name_has_wildcard && end) { - result = NT_STATUS_OBJECT_NAME_INVALID; + status = NT_STATUS_OBJECT_NAME_INVALID; goto fail; } @@ -592,9 +419,9 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx, */ if (posix_pathnames) { - ret = vfs_lstat_smb_fname(conn,name, &st); + ret = SMB_VFS_LSTAT(conn, smb_fname); } else { - ret = vfs_stat_smb_fname(conn,name, &st); + ret = SMB_VFS_STAT(conn, smb_fname); } if (ret == 0) { @@ -602,7 +429,7 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx, * It exists. it must either be a directory or this must * be the last part of the path for it to be OK. */ - if (end && !S_ISDIR(st.st_ex_mode)) { + if (end && !S_ISDIR(smb_fname->st.st_ex_mode)) { /* * An intermediate part of the name isn't * a directory. @@ -617,25 +444,15 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx, * applications depend on the difference between * these two errors. */ - result = NT_STATUS_OBJECT_PATH_NOT_FOUND; + status = NT_STATUS_OBJECT_PATH_NOT_FOUND; goto fail; } - if (!end) { - /* - * We just scanned for, and found the end of - * the path. We must return the valid stat - * struct. JRA. - */ - - smb_fname->st = st; - } - } else { char *found_name = NULL; /* Stat failed - ensure we don't use it. */ - SET_STAT_INVALID(st); + SET_STAT_INVALID(smb_fname->st); /* * Reset errno so we can detect @@ -681,11 +498,11 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx, if (errno == ENOENT || errno == ENOTDIR || errno == ELOOP) { - result = + status = NT_STATUS_OBJECT_PATH_NOT_FOUND; } else { - result = + status = map_nt_error_from_unix(errno); } goto fail; @@ -706,10 +523,10 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx, */ if (errno == ENOTDIR || errno == ELOOP) { - result = + status = NT_STATUS_OBJECT_PATH_NOT_FOUND; } else { - result = + status = map_nt_error_from_unix(errno); } goto fail; @@ -741,12 +558,13 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx, &unmangled, conn->params)) { char *tmp; - size_t start_ofs = start - name; + size_t start_ofs = + start - smb_fname->base_name; if (*dirpath != '\0') { - tmp = talloc_asprintf(ctx, - "%s/%s", dirpath, - unmangled); + tmp = talloc_asprintf( + smb_fname, "%s/%s", + dirpath, unmangled); TALLOC_FREE(unmangled); } else { @@ -754,11 +572,13 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx, } if (tmp == NULL) { DEBUG(0, ("talloc failed\n")); - return NT_STATUS_NO_MEMORY; + status = NT_STATUS_NO_MEMORY; + goto err; } - TALLOC_FREE(name); - name = tmp; - start = name + start_ofs; + TALLOC_FREE(smb_fname->base_name); + smb_fname->base_name = tmp; + start = + smb_fname->base_name + start_ofs; end = start + strlen(start); } @@ -773,46 +593,50 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx, */ if (end) { char *tmp; - size_t start_ofs = start - name; + size_t start_ofs = + start - smb_fname->base_name; if (*dirpath != '\0') { - tmp = talloc_asprintf(ctx, + tmp = talloc_asprintf(smb_fname, "%s/%s/%s", dirpath, found_name, end+1); } else { - tmp = talloc_asprintf(ctx, + tmp = talloc_asprintf(smb_fname, "%s/%s", found_name, end+1); } if (tmp == NULL) { DEBUG(0, ("talloc_asprintf failed\n")); - return NT_STATUS_NO_MEMORY; + status = NT_STATUS_NO_MEMORY; + goto err; } - TALLOC_FREE(name); - name = tmp; - start = name + start_ofs; + TALLOC_FREE(smb_fname->base_name); + smb_fname->base_name = tmp; + start = smb_fname->base_name + start_ofs; end = start + strlen(found_name); *end = '\0'; } else { char *tmp; - size_t start_ofs = start - name; + size_t start_ofs = + start - smb_fname->base_name; if (*dirpath != '\0') { - tmp = talloc_asprintf(ctx, + tmp = talloc_asprintf(smb_fname, "%s/%s", dirpath, found_name); } else { - tmp = talloc_strdup(ctx, + tmp = talloc_strdup(smb_fname, found_name); } if (tmp == NULL) { DEBUG(0, ("talloc failed\n")); - return NT_STATUS_NO_MEMORY; + status = NT_STATUS_NO_MEMORY; + goto err; } - TALLOC_FREE(name); - name = tmp; - start = name + start_ofs; + TALLOC_FREE(smb_fname->base_name); + smb_fname->base_name = tmp; + start = smb_fname->base_name + start_ofs; /* * We just scanned for, and found the end of @@ -821,17 +645,13 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx, */ if (posix_pathnames) { - ret = vfs_lstat_smb_fname(conn,name, - &st); + ret = SMB_VFS_LSTAT(conn, smb_fname); } else { - ret = vfs_stat_smb_fname(conn,name, - &st); + ret = SMB_VFS_STAT(conn, smb_fname); } - if (ret == 0) { - smb_fname->st = st; - } else { - SET_STAT_INVALID(st); + if (ret != 0) { + SET_STAT_INVALID(smb_fname->st); } } @@ -844,12 +664,13 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx, * We should never provide different behaviors * depending on DEVELOPER!!! */ - if (VALID_STAT(st)) { + if (VALID_STAT(smb_fname->st)) { bool delete_pending; - get_file_infos(vfs_file_id_from_sbuf(conn, &st), + get_file_infos(vfs_file_id_from_sbuf(conn, + &smb_fname->st), &delete_pending, NULL); if (delete_pending) { - result = NT_STATUS_DELETE_PENDING; + status = NT_STATUS_DELETE_PENDING; goto fail; } } @@ -864,7 +685,8 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx, "%s/%s", dirpath, start); if (!tmp) { DEBUG(0, ("talloc_asprintf failed\n")); - return NT_STATUS_NO_MEMORY; + status = NT_STATUS_NO_MEMORY; + goto err; } TALLOC_FREE(dirpath); dirpath = tmp; @@ -873,15 +695,15 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx, TALLOC_FREE(dirpath); if (!(dirpath = talloc_strdup(ctx,start))) { DEBUG(0, ("talloc_strdup failed\n")); - return NT_STATUS_NO_MEMORY; + status = NT_STATUS_NO_MEMORY; + goto err; } } /* - * Don't cache a name with mangled or wildcard components - * as this can change the size. + * Cache the dirpath thus far. Don't cache a name with mangled + * or wildcard components as this can change the size. */ - if(!component_was_mangled && !name_has_wildcard) { stat_cache_add(orig_path, dirpath, conn->case_sensitive); @@ -896,29 +718,30 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx, } /* - * Don't cache a name with mangled or wildcard components - * as this can change the size. + * Cache the full path. Don't cache a name with mangled or wildcard + * components as this can change the size. */ if(!component_was_mangled && !name_has_wildcard) { - stat_cache_add(orig_path, name, conn->case_sensitive); + stat_cache_add(orig_path, smb_fname->base_name, + conn->case_sensitive); } /* * The name has been resolved. */ - DEBUG(5,("conversion finished %s -> %s\n",orig_path, name)); + DEBUG(5,("conversion finished %s -> %s\n", orig_path, + smb_fname->base_name)); done: - smb_fname->base_name = name; - + /* Add back the stream if one was stripped off originally. */ if (stream != NULL) { smb_fname->stream_name = stream; /* Check path now that the base_name has been converted. */ - result = build_stream_path(ctx, conn, orig_path, smb_fname); - if (!NT_STATUS_IS_OK(result)) { + status = build_stream_path(ctx, conn, orig_path, smb_fname); + if (!NT_STATUS_IS_OK(status)) { goto fail; } } @@ -928,20 +751,23 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx, fail: DEBUG(10, ("dirpath = [%s] start = [%s]\n", dirpath, start)); if (*dirpath != '\0') { - smb_fname->base_name = talloc_asprintf(ctx, "%s/%s", dirpath, - start); + smb_fname->base_name = talloc_asprintf(smb_fname, "%s/%s", + dirpath, start); } else { - smb_fname->base_name = talloc_strdup(ctx, start); + smb_fname->base_name = talloc_strdup(smb_fname, start); } if (!smb_fname->base_name) { DEBUG(0, ("talloc_asprintf failed\n")); - return NT_STATUS_NO_MEMORY; + status = NT_STATUS_NO_MEMORY; + goto err; } *smb_fname_out = smb_fname; - TALLOC_FREE(name); TALLOC_FREE(dirpath); - return result; + return status; + err: + TALLOC_FREE(smb_fname); + return status; } /**************************************************************************** @@ -1137,6 +963,7 @@ static NTSTATUS build_stream_path(TALLOC_CTX *mem_ctx, struct stream_struct *streams = NULL; if (SMB_VFS_STAT(conn, smb_fname) == 0) { + DEBUG(10, ("'%s' exists\n", smb_fname_str_dbg(smb_fname))); return NT_STATUS_OK; } @@ -1183,21 +1010,16 @@ static NTSTATUS build_stream_path(TALLOC_CTX *mem_ctx, TALLOC_FREE(smb_fname->stream_name); - smb_fname->stream_name = talloc_strdup(mem_ctx, streams[i].name); + smb_fname->stream_name = talloc_strdup(smb_fname, streams[i].name); + if (smb_fname->stream_name == NULL) { + status = NT_STATUS_NO_MEMORY; + goto fail; + } SET_STAT_INVALID(smb_fname->st); if (SMB_VFS_STAT(conn, smb_fname) == 0) { - char *result = NULL; - - status = get_full_smb_filename(mem_ctx, smb_fname, &result); - if (!NT_STATUS_IS_OK(status)) { - status = NT_STATUS_NO_MEMORY; - goto fail; - } - - stat_cache_add(orig_path, result, conn->case_sensitive); - TALLOC_FREE(result); + DEBUG(10, ("'%s' exists\n", smb_fname_str_dbg(smb_fname))); } status = NT_STATUS_OK; fail: @@ -1213,8 +1035,7 @@ NTSTATUS filename_convert(TALLOC_CTX *ctx, connection_struct *conn, bool dfs_path, const char *name_in, - struct smb_filename **pp_smb_fname, - char **pp_name) + struct smb_filename **pp_smb_fname) { NTSTATUS status; char *fname = NULL; @@ -1241,22 +1062,15 @@ NTSTATUS filename_convert(TALLOC_CTX *ctx, return status; } - status = get_full_smb_filename(ctx, *pp_smb_fname, &fname); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - status = check_name(conn, fname); + status = check_name(conn, (*pp_smb_fname)->base_name); if (!NT_STATUS_IS_OK(status)) { DEBUG(3,("filename_convert: check_name failed " "for name %s with %s\n", - fname, + smb_fname_str_dbg(*pp_smb_fname), nt_errstr(status) )); + TALLOC_FREE(*pp_smb_fname); return status; } - if (pp_name != NULL) { - *pp_name = fname; - } return status; } diff --git a/source3/smbd/filename_util.c b/source3/smbd/filename_util.c new file mode 100644 index 0000000000..867709a373 --- /dev/null +++ b/source3/smbd/filename_util.c @@ -0,0 +1,206 @@ +/* + Unix SMB/CIFS implementation. + Filename utility functions. + Copyright (C) Tim Prouty 2009 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ +#include "includes.h" + +/** + * XXX: This is temporary and there should be no callers of this outside of + * this file once smb_filename is plumbed through all path based operations. + * The one legitimate caller currently is smb_fname_str_dbg(), which this + * could be made static for. + */ +NTSTATUS get_full_smb_filename(TALLOC_CTX *ctx, + const struct smb_filename *smb_fname, + char **full_name) +{ + if (smb_fname->stream_name) { + /* stream_name must always be NULL if there is no stream. */ + SMB_ASSERT(smb_fname->stream_name[0] != '\0'); + + *full_name = talloc_asprintf(ctx, "%s%s", smb_fname->base_name, + smb_fname->stream_name); + } else { + *full_name = talloc_strdup(ctx, smb_fname->base_name); + } + + if (!*full_name) { + return NT_STATUS_NO_MEMORY; + } + + return NT_STATUS_OK; +} + +/** + * There are actually legitimate callers of this such as functions that + * enumerate streams using the SMB_VFS_STREAMINFO interface and then want to + * operate on each stream. + */ +NTSTATUS create_synthetic_smb_fname(TALLOC_CTX *ctx, const char *base_name, + const char *stream_name, + const SMB_STRUCT_STAT *psbuf, + struct smb_filename **smb_fname_out) +{ + struct smb_filename smb_fname_loc; + + ZERO_STRUCT(smb_fname_loc); + + /* Setup the base_name/stream_name. */ + smb_fname_loc.base_name = CONST_DISCARD(char *, base_name); + smb_fname_loc.stream_name = CONST_DISCARD(char *, stream_name); + + /* Copy the psbuf if one was given. */ + if (psbuf) + smb_fname_loc.st = *psbuf; + + /* Let copy_smb_filename() do the heavy lifting. */ + return copy_smb_filename(ctx, &smb_fname_loc, smb_fname_out); +} + +/** + * XXX: This is temporary and there should be no callers of this once + * smb_filename is plumbed through all path based operations. + */ +NTSTATUS create_synthetic_smb_fname_split(TALLOC_CTX *ctx, + const char *fname, + const SMB_STRUCT_STAT *psbuf, + struct smb_filename **smb_fname_out) +{ + NTSTATUS status; + const char *stream_name = NULL; + char *base_name = NULL; + + if (!lp_posix_pathnames()) { + stream_name = strchr_m(fname, ':'); + } + + /* Setup the base_name/stream_name. */ + if (stream_name) { + base_name = talloc_strndup(ctx, fname, + PTR_DIFF(stream_name, fname)); + } else { + base_name = talloc_strdup(ctx, fname); + } + + if (!base_name) { + return NT_STATUS_NO_MEMORY; + } + + status = create_synthetic_smb_fname(ctx, base_name, stream_name, psbuf, + smb_fname_out); + TALLOC_FREE(base_name); + return status; +} + +/** + * Return a string using the debug_ctx() + */ +const char *smb_fname_str_dbg(const struct smb_filename *smb_fname) +{ + char *fname = NULL; + NTSTATUS status; + + if (smb_fname == NULL) { + return ""; + } + status = get_full_smb_filename(debug_ctx(), smb_fname, &fname); + if (!NT_STATUS_IS_OK(status)) { + return ""; + } + return fname; +} + +/** + * Return a debug string using the debug_ctx(). This can only be called from + * DEBUG() macros due to the debut_ctx(). + */ +const char *fsp_str_dbg(const struct files_struct *fsp) +{ + return smb_fname_str_dbg(fsp->fsp_name); +} + +NTSTATUS copy_smb_filename(TALLOC_CTX *ctx, + const struct smb_filename *smb_fname_in, + struct smb_filename **smb_fname_out) +{ + /* stream_name must always be NULL if there is no stream. */ + if (smb_fname_in->stream_name) { + SMB_ASSERT(smb_fname_in->stream_name[0] != '\0'); + } + + *smb_fname_out = talloc_zero(ctx, struct smb_filename); + if (*smb_fname_out == NULL) { + return NT_STATUS_NO_MEMORY; + } + + if (smb_fname_in->base_name) { + (*smb_fname_out)->base_name = + talloc_strdup(*smb_fname_out, smb_fname_in->base_name); + if (!(*smb_fname_out)->base_name) + goto no_mem_err; + } + + if (smb_fname_in->stream_name) { + (*smb_fname_out)->stream_name = + talloc_strdup(*smb_fname_out, smb_fname_in->stream_name); + if (!(*smb_fname_out)->stream_name) + goto no_mem_err; + } + + if (smb_fname_in->original_lcomp) { + (*smb_fname_out)->original_lcomp = + talloc_strdup(*smb_fname_out, smb_fname_in->original_lcomp); + if (!(*smb_fname_out)->original_lcomp) + goto no_mem_err; + } + + (*smb_fname_out)->st = smb_fname_in->st; + return NT_STATUS_OK; + + no_mem_err: + TALLOC_FREE(*smb_fname_out); + return NT_STATUS_NO_MEMORY; +} + +/**************************************************************************** + Simple check to determine if the filename is a stream. + ***************************************************************************/ +bool is_ntfs_stream_smb_fname(const struct smb_filename *smb_fname) +{ + /* stream_name must always be NULL if there is no stream. */ + if (smb_fname->stream_name) { + SMB_ASSERT(smb_fname->stream_name[0] != '\0'); + } + + if (lp_posix_pathnames()) { + return false; + } + + return smb_fname->stream_name; +} + +/**************************************************************************** + Returns true if the filename's stream == "::$DATA" + ***************************************************************************/ +bool is_ntfs_default_stream_smb_fname(const struct smb_filename *smb_fname) +{ + if (!is_ntfs_stream_smb_fname(smb_fname)) { + return false; + } + + return StrCaseCmp(smb_fname->stream_name, "::$DATA") == 0; +} diff --git a/source3/smbd/files.c b/source3/smbd/files.c index 0e6dd7e457..a170f774fe 100644 --- a/source3/smbd/files.c +++ b/source3/smbd/files.c @@ -44,6 +44,7 @@ NTSTATUS file_new(struct smb_request *req, connection_struct *conn, { int i; files_struct *fsp; + NTSTATUS status; /* we want to give out file handles differently on each new connection because of a common bug in MS clients where they try to @@ -65,21 +66,26 @@ NTSTATUS file_new(struct smb_request *req, connection_struct *conn, return NT_STATUS_TOO_MANY_OPENED_FILES; } - fsp = SMB_MALLOC_P(files_struct); + /* + * Make a child of the connection_struct as an fsp can't exist + * indepenedent of a connection. + */ + fsp = talloc_zero(conn, struct files_struct); if (!fsp) { return NT_STATUS_NO_MEMORY; } - ZERO_STRUCTP(fsp); - - fsp->fh = SMB_MALLOC_P(struct fd_handle); + /* + * This can't be a child of fsp because the file_handle can be ref'd + * when doing a dos/fcb open, which will then share the file_handle + * across multiple fsps. + */ + fsp->fh = talloc_zero(conn, struct fd_handle); if (!fsp->fh) { - SAFE_FREE(fsp); + TALLOC_FREE(fsp); return NT_STATUS_NO_MEMORY; } - ZERO_STRUCTP(fsp->fh); - fsp->fh->ref_count = 1; fsp->fh->fd = -1; @@ -95,8 +101,18 @@ NTSTATUS file_new(struct smb_request *req, connection_struct *conn, fsp->fnum = i + FILE_HANDLE_OFFSET; SMB_ASSERT(fsp->fnum < 65536); - string_set(&fsp->fsp_name,""); - + /* + * Create an smb_filename with "" for the base_name. There are very + * few NULL checks, so make sure it's initialized with something. to + * be safe until an audit can be done. + */ + status = create_synthetic_smb_fname(fsp, "", NULL, NULL, + &fsp->fsp_name); + if (!NT_STATUS_IS_OK(status)) { + TALLOC_FREE(fsp); + TALLOC_FREE(fsp->fh); + } + DLIST_ADD(Files, fsp); DEBUG(5,("allocated file structure %d, fnum = %d (%d used)\n", @@ -236,8 +252,9 @@ void file_dump_open_table(void) files_struct *fsp; for (fsp=Files;fsp;fsp=fsp->next,count++) { - DEBUG(10,("Files[%d], fnum = %d, name %s, fd = %d, gen = %lu, fileid=%s\n", - count, fsp->fnum, fsp->fsp_name, fsp->fh->fd, (unsigned long)fsp->fh->gen_id, + DEBUG(10,("Files[%d], fnum = %d, name %s, fd = %d, gen = %lu, " + "fileid=%s\n", count, fsp->fnum, fsp_str_dbg(fsp), + fsp->fh->fd, (unsigned long)fsp->fh->gen_id, file_id_string_tos(&fsp->file_id))); } } @@ -283,8 +300,10 @@ files_struct *file_find_dif(struct file_id id, unsigned long gen_id) if ((fsp->fh->fd == -1) && (fsp->oplock_type != NO_OPLOCK) && (fsp->oplock_type != FAKE_LEVEL_II_OPLOCK)) { - DEBUG(0,("file_find_dif: file %s file_id = %s, gen = %u \ -oplock_type = %u is a stat open with oplock type !\n", fsp->fsp_name, + DEBUG(0,("file_find_dif: file %s file_id = " + "%s, gen = %u oplock_type = %u is a " + "stat open with oplock type !\n", + fsp_str_dbg(fsp), file_id_string_tos(&fsp->file_id), (unsigned int)fsp->fh->gen_id, (unsigned int)fsp->oplock_type )); @@ -385,10 +404,11 @@ bool file_find_subpath(files_struct *dir_fsp) { files_struct *fsp; size_t dlen; - char *d_fullname = talloc_asprintf(talloc_tos(), - "%s/%s", - dir_fsp->conn->connectpath, - dir_fsp->fsp_name); + char *d_fullname; + + d_fullname = talloc_asprintf(talloc_tos(), "%s/%s", + dir_fsp->conn->connectpath, + dir_fsp->fsp_name->base_name); if (!d_fullname) { return false; @@ -406,7 +426,7 @@ bool file_find_subpath(files_struct *dir_fsp) d1_fullname = talloc_asprintf(talloc_tos(), "%s/%s", fsp->conn->connectpath, - fsp->fsp_name); + fsp->fsp_name->base_name); if (strnequal(d_fullname, d1_fullname, dlen)) { TALLOC_FREE(d_fullname); @@ -444,12 +464,10 @@ void file_free(struct smb_request *req, files_struct *fsp) { DLIST_REMOVE(Files, fsp); - string_free(&fsp->fsp_name); - TALLOC_FREE(fsp->fake_file_handle); if (fsp->fh->ref_count == 1) { - SAFE_FREE(fsp->fh); + TALLOC_FREE(fsp->fh); } else { fsp->fh->ref_count--; } @@ -495,7 +513,8 @@ void file_free(struct smb_request *req, files_struct *fsp) information */ ZERO_STRUCTP(fsp); - SAFE_FREE(fsp); + /* fsp->fsp_name is a talloc child and is free'd automatically. */ + TALLOC_FREE(fsp); } /**************************************************************************** @@ -541,11 +560,11 @@ files_struct *file_fsp(struct smb_request *req, uint16 fid) Duplicate the file handle part for a DOS or FCB open. ****************************************************************************/ -void dup_file_fsp(struct smb_request *req, files_struct *from, +NTSTATUS dup_file_fsp(struct smb_request *req, files_struct *from, uint32 access_mask, uint32 share_access, uint32 create_options, files_struct *to) { - SAFE_FREE(to->fh); + TALLOC_FREE(to->fh); to->fh = from->fh; to->fh->ref_count++; @@ -570,5 +589,25 @@ void dup_file_fsp(struct smb_request *req, files_struct *from, to->modified = from->modified; to->is_directory = from->is_directory; to->aio_write_behind = from->aio_write_behind; - string_set(&to->fsp_name,from->fsp_name); + return fsp_set_smb_fname(to, from->fsp_name); +} + +/** + * The only way that the fsp->fsp_name field should ever be set. + */ +NTSTATUS fsp_set_smb_fname(struct files_struct *fsp, + const struct smb_filename *smb_fname_in) +{ + NTSTATUS status; + struct smb_filename *smb_fname_new; + + status = copy_smb_filename(fsp, smb_fname_in, &smb_fname_new); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + TALLOC_FREE(fsp->fsp_name); + fsp->fsp_name = smb_fname_new; + + return NT_STATUS_OK; } diff --git a/source3/smbd/globals.c b/source3/smbd/globals.c index 15550ed455..317304a86d 100644 --- a/source3/smbd/globals.c +++ b/source3/smbd/globals.c @@ -153,4 +153,9 @@ void smbd_init_globals(void) ZERO_STRUCT(conn_ctx_stack); ZERO_STRUCT(sec_ctx_stack); + + smbd_server_conn = talloc_zero(smbd_event_context(), struct smbd_server_connection); + if (!smbd_server_conn) { + exit_server("failed to create smbd_server_connection"); + } } diff --git a/source3/smbd/globals.h b/source3/smbd/globals.h index 3d195c84f0..434204b60d 100644 --- a/source3/smbd/globals.h +++ b/source3/smbd/globals.h @@ -168,6 +168,56 @@ NTSTATUS smb2_signing_check_pdu(DATA_BLOB session_key, const struct iovec *vector, int count); +struct smbd_lock_element { + uint32_t smbpid; + enum brl_type brltype; + uint64_t offset; + uint64_t count; +}; + +NTSTATUS smbd_do_locking(struct smb_request *req, + files_struct *fsp, + uint8_t type, + int32_t timeout, + uint16_t num_ulocks, + struct smbd_lock_element *ulocks, + uint16_t num_locks, + struct smbd_lock_element *locks, + bool *async); + +NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn, + TALLOC_CTX *mem_ctx, + uint16_t info_level, + files_struct *fsp, + const struct smb_filename *smb_fname, + bool delete_pending, + struct timespec write_time_ts, + bool ms_dfs_link, + struct ea_list *ea_list, + int lock_data_count, + char *lock_data, + uint16_t flags2, + unsigned int max_data_bytes, + char **ppdata, + unsigned int *pdata_size); + +NTSTATUS smbd_do_setfilepathinfo(connection_struct *conn, + struct smb_request *req, + TALLOC_CTX *mem_ctx, + uint16_t info_level, + files_struct *fsp, + struct smb_filename *smb_fname, + char **ppdata, int total_data, + int *ret_data_size); + +NTSTATUS smbd_do_qfsinfo(connection_struct *conn, + TALLOC_CTX *mem_ctx, + uint16_t info_level, + uint16_t flags2, + unsigned int max_data_bytes, + char **ppdata, + int *ret_data_len); + void smbd_server_connection_terminate_ex(struct smbd_server_connection *sconn, const char *reason, const char *location); diff --git a/source3/smbd/ipc.c b/source3/smbd/ipc.c index 1067dab074..96a411dd70 100644 --- a/source3/smbd/ipc.c +++ b/source3/smbd/ipc.c @@ -454,7 +454,7 @@ static void api_fd_reply(connection_struct *conn, uint16 vuid, } DEBUG(3,("Got API command 0x%x on pipe \"%s\" (pnum %x)\n", - subcommand, fsp->fsp_name, pnum)); + subcommand, fsp_str_dbg(fsp), pnum)); DEBUG(10, ("api_fd_reply: p:%p max_trans_reply: %d\n", fsp, mdrcnt)); diff --git a/source3/smbd/msdfs.c b/source3/smbd/msdfs.c index d40b8a8902..2b63eb1743 100644 --- a/source3/smbd/msdfs.c +++ b/source3/smbd/msdfs.c @@ -411,7 +411,6 @@ static bool is_msdfs_link_internal(TALLOC_CTX *ctx, char **pp_link_target, SMB_STRUCT_STAT *sbufp) { - SMB_STRUCT_STAT st; int referral_len = 0; #if defined(HAVE_BROKEN_READLINK) char link_target_buf[PATH_MAX]; @@ -420,6 +419,8 @@ static bool is_msdfs_link_internal(TALLOC_CTX *ctx, #endif size_t bufsize = 0; char *link_target = NULL; + struct smb_filename *smb_fname = NULL; + NTSTATUS status; if (pp_link_target) { bufsize = 1024; @@ -433,21 +434,28 @@ static bool is_msdfs_link_internal(TALLOC_CTX *ctx, link_target = link_target_buf; } - if (sbufp == NULL) { - sbufp = &st; + status = create_synthetic_smb_fname(talloc_tos(), path, NULL, NULL, + &smb_fname); + if (!NT_STATUS_IS_OK(status)) { + goto err; } - if (vfs_lstat_smb_fname(conn, path, sbufp) != 0) { + if (SMB_VFS_LSTAT(conn, smb_fname) != 0) { DEBUG(5,("is_msdfs_link_read_target: %s does not exist.\n", path)); + TALLOC_FREE(smb_fname); goto err; } - - if (!S_ISLNK(sbufp->st_ex_mode)) { + if (!S_ISLNK(smb_fname->st.st_ex_mode)) { DEBUG(5,("is_msdfs_link_read_target: %s is not a link.\n", path)); + TALLOC_FREE(smb_fname); goto err; } + if (sbufp != NULL) { + *sbufp = smb_fname->st; + } + TALLOC_FREE(smb_fname); referral_len = SMB_VFS_READLINK(conn, path, link_target, bufsize - 1); if (referral_len == -1) { diff --git a/source3/smbd/notify.c b/source3/smbd/notify.c index ded888c021..8f37923865 100644 --- a/source3/smbd/notify.c +++ b/source3/smbd/notify.c @@ -182,7 +182,7 @@ void change_notify_reply(connection_struct *conn, static void notify_callback(void *private_data, const struct notify_event *e) { files_struct *fsp = (files_struct *)private_data; - DEBUG(10, ("notify_callback called for %s\n", fsp->fsp_name)); + DEBUG(10, ("notify_callback called for %s\n", fsp_str_dbg(fsp))); notify_fsp(fsp, e->action, e->path); } @@ -200,8 +200,9 @@ NTSTATUS change_notify_create(struct files_struct *fsp, uint32 filter, return NT_STATUS_NO_MEMORY; } + /* Do notify operations on the base_name. */ if (asprintf(&fullpath, "%s/%s", fsp->conn->connectpath, - fsp->fsp_name) == -1) { + fsp->fsp_name->base_name) == -1) { DEBUG(0, ("asprintf failed\n")); TALLOC_FREE(fsp->notify); return NT_STATUS_NO_MEMORY; @@ -236,7 +237,7 @@ NTSTATUS change_notify_add_request(struct smb_request *req, struct smbd_server_connection *sconn = smbd_server_conn; DEBUG(10, ("change_notify_add_request: Adding request for %s: " - "max_param = %d\n", fsp->fsp_name, (int)max_param)); + "max_param = %d\n", fsp_str_dbg(fsp), (int)max_param)); if (!(request = talloc(NULL, struct notify_change_request)) || !(map = talloc(request, struct notify_mid_map))) { diff --git a/source3/smbd/nttrans.c b/source3/smbd/nttrans.c index b65af26eca..43212dc800 100644 --- a/source3/smbd/nttrans.c +++ b/source3/smbd/nttrans.c @@ -272,30 +272,6 @@ void send_nt_replies(connection_struct *conn, } /**************************************************************************** - Simple check to determine if the filename is a stream. - ***************************************************************************/ -bool is_ntfs_stream_smb_fname(const struct smb_filename *smb_fname) -{ - if (lp_posix_pathnames()) { - return false; - } - - return smb_fname->stream_name; -} - -/**************************************************************************** - Returns true if the filename's stream == "::$DATA" - ***************************************************************************/ -bool is_ntfs_default_stream_smb_fname(const struct smb_filename *smb_fname) -{ - if (!is_ntfs_stream_smb_fname(smb_fname)) { - return false; - } - - return StrCaseCmp(smb_fname->stream_name, "::$DATA") == 0; -} - -/**************************************************************************** Reply to an NT create and X call on a pipe ****************************************************************************/ @@ -502,8 +478,7 @@ void reply_ntcreate_and_X(struct smb_request *req) conn, req->flags2 & FLAGS2_DFS_PATHNAMES, fname, - &smb_fname, - NULL); + &smb_fname); if (!NT_STATUS_IS_OK(status)) { if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { @@ -794,7 +769,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); } @@ -992,8 +967,7 @@ static void call_nt_transact_create(connection_struct *conn, conn, req->flags2 & FLAGS2_DFS_PATHNAMES, fname, - &smb_fname, - NULL); + &smb_fname); if (!NT_STATUS_IS_OK(status)) { if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { @@ -1341,8 +1315,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); @@ -1353,14 +1326,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++; @@ -1368,55 +1339,83 @@ 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 = filename_convert(ctx, conn, - req->flags2 & FLAGS2_DFS_PATHNAMES, - oldname, - &smb_fname_old, - &oldname); - 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); - END_PROFILE(SMBntrename); - return; - } - reply_nterror(req, status); - END_PROFILE(SMBntrename); - return; + /* 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; } - status = filename_convert(ctx, conn, - req->flags2 & FLAGS2_DFS_PATHNAMES, - newname, - &smb_fname_new, - &newname); - 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); - END_PROFILE(SMBntrename); - return; + /* rename_internals() calls unix_convert(), so don't call it here. */ + if (rename_type != RENAME_FLAG_RENAME) { + status = filename_convert(ctx, conn, + req->flags2 & FLAGS2_DFS_PATHNAMES, + oldname, + &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, + ERRSRV, ERRbadpath); + goto out; + } + reply_nterror(req, status); + 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_smb_fname(smb_fname_old) && (newname[0] != ':')) { - reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - END_PROFILE(SMBntrename); - return; - } + status = filename_convert(ctx, conn, + req->flags2 & FLAGS2_DFS_PATHNAMES, + newname, + &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, + ERRSRV, ERRbadpath); + goto out; + } + reply_nterror(req, status); + 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 = resolve_dfspath(ctx, conn, + (req->flags2 & + FLAGS2_DFS_PATHNAMES), + oldname, &oldname); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(10,("resolve_dfspath failed for name %s " + "with %s\n", oldname, + nt_errstr(status))); + reply_nterror(req, status); + goto out; + } + + status = resolve_dfspath(ctx, conn, + (req->flags2 & + FLAGS2_DFS_PATHNAMES), + newname, &newname); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(10,("resolve_dfspath failed for name %s " + "with %s\n", newname, + nt_errstr(status))); + reply_nterror(req, status); + goto out; + } + + DEBUG(3,("reply_ntrename: %s -> %s\n", oldname, + newname)); + status = rename_internals(ctx, conn, req, oldname, newname, attrs, False, src_has_wcard, dest_has_wcard, DELETE_ACCESS); @@ -1454,17 +1453,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; } @@ -1523,7 +1520,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); } @@ -1626,7 +1623,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; } @@ -1684,8 +1681,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) { @@ -1722,7 +1720,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); } @@ -1796,8 +1795,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); @@ -2021,7 +2020,7 @@ static void call_nt_transact_ioctl(connection_struct *conn, 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;i<shadow_data->num_volumes;i++) { srvstr_push(pdata, req->flags2, diff --git a/source3/smbd/open.c b/source3/smbd/open.c index e01350f2bf..87cab1966b 100644 --- a/source3/smbd/open.c +++ b/source3/smbd/open.c @@ -94,6 +94,7 @@ static NTSTATUS check_open_rights(struct connection_struct *conn, "on %s: %s\n", smb_fname_str_dbg(smb_fname), nt_errstr(status))); + TALLOC_FREE(sd); return status; } @@ -218,13 +219,13 @@ void change_file_owner_to_parent(connection_struct *conn, if (ret == -1) { DEBUG(0,("change_file_owner_to_parent: failed to fchown " "file %s to parent directory uid %u. Error " - "was %s\n", fsp->fsp_name, + "was %s\n", fsp_str_dbg(fsp), (unsigned int)smb_fname_parent->st.st_ex_uid, strerror(errno) )); } DEBUG(10,("change_file_owner_to_parent: changed new file %s to " - "parent directory uid %u.\n", fsp->fsp_name, + "parent directory uid %u.\n", fsp_str_dbg(fsp), (unsigned int)smb_fname_parent->st.st_ex_uid)); TALLOC_FREE(smb_fname_parent); @@ -349,7 +350,6 @@ static NTSTATUS open_file(files_struct *fsp, uint32 access_mask, /* client requested access mask. */ uint32 open_access_mask) /* what we're actually using in the open. */ { - char *path = NULL; NTSTATUS status = NT_STATUS_OK; int accmode = (flags & O_ACCMODE); int local_flags = flags; @@ -434,7 +434,7 @@ static NTSTATUS open_file(files_struct *fsp, * wildcard characters are allowed in stream names * only test the basefilename */ - wild = fsp->base_fsp->fsp_name; + wild = fsp->base_fsp->fsp_name->base_name; } else { wild = smb_fname->base_name; } @@ -614,16 +614,13 @@ static NTSTATUS open_file(files_struct *fsp, conn->case_sensitive)) { fsp->aio_write_behind = True; } - - status = get_full_smb_filename(talloc_tos(), smb_fname, - &path); + status = fsp_set_smb_fname(fsp, smb_fname); if (!NT_STATUS_IS_OK(status)) { + fd_close(fsp); + errno = map_errno_from_nt_status(status); return status; } - string_set(&fsp->fsp_name, path); - TALLOC_FREE(path); - fsp->wcp = NULL; /* Write cache pointer. */ DEBUG(2,("%s opened file %s read=%s write=%s (numopen=%d)\n", @@ -795,7 +792,8 @@ static void validate_my_share_entries(int num, str = talloc_asprintf(talloc_tos(), "validate_my_share_entries: " "file %s, oplock_type = 0x%x, op_type = 0x%x\n", - fsp->fsp_name, (unsigned int)fsp->oplock_type, + fsp->fsp_name->base_name, + (unsigned int)fsp->oplock_type, (unsigned int)share_entry->op_type ); smb_panic(str); } @@ -1029,7 +1027,7 @@ static bool delay_for_oplocks(struct share_mode_lock *lck, } DEBUG(10,("delay_for_oplocks: oplock type 0x%x on file %s\n", - fsp->oplock_type, fsp->fsp_name)); + fsp->oplock_type, fsp_str_dbg(fsp))); /* No delay. */ return false; @@ -1152,13 +1150,6 @@ NTSTATUS fcb_or_dos_open(struct smb_request *req, uint32 create_options) { files_struct *fsp; - char *fname = NULL; - NTSTATUS status; - - status = get_full_smb_filename(talloc_tos(), smb_fname, &fname); - if (!NT_STATUS_IS_OK(status)) { - return status; - } DEBUG(5,("fcb_or_dos_open: attempting old open semantics for " "file %s.\n", smb_fname_str_dbg(smb_fname))); @@ -1168,7 +1159,7 @@ NTSTATUS fcb_or_dos_open(struct smb_request *req, DEBUG(10,("fcb_or_dos_open: checking file %s, fd = %d, " "vuid = %u, file_pid = %u, private_options = 0x%x " - "access_mask = 0x%x\n", fsp->fsp_name, + "access_mask = 0x%x\n", fsp_str_dbg(fsp), fsp->fh->fd, (unsigned int)fsp->vuid, (unsigned int)fsp->file_pid, (unsigned int)fsp->fh->private_options, @@ -1180,7 +1171,9 @@ NTSTATUS fcb_or_dos_open(struct smb_request *req, (fsp->fh->private_options & (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS | NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) && (fsp->access_mask & FILE_WRITE_DATA) && - strequal(fsp->fsp_name, fname)) { + strequal(fsp->fsp_name->base_name, smb_fname->base_name) && + strequal(fsp->fsp_name->stream_name, + smb_fname->stream_name)) { DEBUG(10,("fcb_or_dos_open: file match\n")); break; } @@ -1198,17 +1191,16 @@ NTSTATUS fcb_or_dos_open(struct smb_request *req, } /* We need to duplicate this fsp. */ - dup_file_fsp(req, fsp, access_mask, share_access, - create_options, fsp_to_dup_into); - - return NT_STATUS_OK; + return dup_file_fsp(req, fsp, access_mask, share_access, + create_options, fsp_to_dup_into); } /**************************************************************************** Open a file with a share mode - old openX method - map into NTCreate. ****************************************************************************/ -bool map_open_params_to_ntcreate(const char *fname, int deny_mode, int open_func, +bool map_open_params_to_ntcreate(const struct smb_filename *smb_fname, + int deny_mode, int open_func, uint32 *paccess_mask, uint32 *pshare_mode, uint32 *pcreate_disposition, @@ -1221,7 +1213,8 @@ bool map_open_params_to_ntcreate(const char *fname, int deny_mode, int open_func DEBUG(10,("map_open_params_to_ntcreate: fname = %s, deny_mode = 0x%x, " "open_func = 0x%x\n", - fname, (unsigned int)deny_mode, (unsigned int)open_func )); + smb_fname_str_dbg(smb_fname), (unsigned int)deny_mode, + (unsigned int)open_func )); /* Create the NT compatible access_mask. */ switch (GET_OPENX_MODE(deny_mode)) { @@ -1295,7 +1288,7 @@ bool map_open_params_to_ntcreate(const char *fname, int deny_mode, int open_func case DENY_DOS: create_options |= NTCREATEX_OPTIONS_PRIVATE_DENY_DOS; - if (is_executable(fname)) { + if (is_executable(smb_fname->base_name)) { share_mode = FILE_SHARE_READ|FILE_SHARE_WRITE; } else { if (GET_OPENX_MODE(deny_mode) == DOS_OPEN_RDONLY) { @@ -1320,7 +1313,7 @@ bool map_open_params_to_ntcreate(const char *fname, int deny_mode, int open_func DEBUG(10,("map_open_params_to_ntcreate: file %s, access_mask = 0x%x, " "share_mode = 0x%x, create_disposition = 0x%x, " "create_options = 0x%x\n", - fname, + smb_fname_str_dbg(smb_fname), (unsigned int)access_mask, (unsigned int)share_mode, (unsigned int)create_disposition, @@ -2611,8 +2604,10 @@ static NTSTATUS open_directory(connection_struct *conn, fsp->sent_oplock_break = NO_BREAK_SENT; fsp->is_directory = True; fsp->posix_open = (file_attributes & FILE_FLAG_POSIX_SEMANTICS) ? True : False; - - string_set(&fsp->fsp_name, smb_dname->base_name); + status = fsp_set_smb_fname(fsp, smb_dname); + if (!NT_STATUS_IS_OK(status)) { + return status; + } mtimespec = smb_dname->st.st_ex_mtime; @@ -2730,6 +2725,11 @@ void msg_file_was_renamed(struct messaging_context *msg, bn_len = strlen(base_name); stream_name = sharepath + sp_len + 1 + bn_len + 1; + /* stream_name must always be NULL if there is no stream. */ + if (stream_name[0] == '\0') { + stream_name = NULL; + } + status = create_synthetic_smb_fname(talloc_tos(), base_name, stream_name, NULL, &smb_fname); if (!NT_STATUS_IS_OK(status)) { @@ -2743,18 +2743,14 @@ void msg_file_was_renamed(struct messaging_context *msg, for(fsp = file_find_di_first(id); fsp; fsp = file_find_di_next(fsp)) { if (memcmp(fsp->conn->connectpath, sharepath, sp_len) == 0) { - char *newname = NULL; DEBUG(10,("msg_file_was_renamed: renaming file fnum %d from %s -> %s\n", - fsp->fnum, fsp->fsp_name, + fsp->fnum, fsp_str_dbg(fsp), smb_fname_str_dbg(smb_fname))); - status = get_full_smb_filename(talloc_tos(), - smb_fname, &newname); + status = fsp_set_smb_fname(fsp, smb_fname); if (!NT_STATUS_IS_OK(status)) { goto out; } - string_set(&fsp->fsp_name, newname); - TALLOC_FREE(newname); } else { /* TODO. JRA. */ /* Now we have the complete path we can work out if this is @@ -2765,7 +2761,7 @@ void msg_file_was_renamed(struct messaging_context *msg, fsp->conn->connectpath, sharepath, fsp->fnum, - fsp->fsp_name, + fsp_str_dbg(fsp), smb_fname_str_dbg(smb_fname))); } } @@ -2926,7 +2922,7 @@ NTSTATUS open_streams_for_delete(connection_struct *conn, } DEBUG(10, ("Closing stream # %d, %s\n", i, - streams[i]->fsp_name)); + fsp_str_dbg(streams[i]))); close_file(NULL, streams[i], NORMAL_CLOSE); } @@ -3326,6 +3322,11 @@ NTSTATUS get_relative_fid_filename(connection_struct *conn, dir_fsp = file_fsp(req, root_dir_fid); + if (is_ntfs_stream_smb_fname(dir_fsp->fsp_name)) { + status = NT_STATUS_INVALID_HANDLE; + goto out; + } + if (dir_fsp == NULL) { status = NT_STATUS_INVALID_HANDLE; goto out; @@ -3354,7 +3355,7 @@ NTSTATUS get_relative_fid_filename(connection_struct *conn, goto out; } - if (ISDOT(dir_fsp->fsp_name)) { + if (ISDOT(dir_fsp->fsp_name->base_name)) { /* * We're at the toplevel dir, the final file name * must not contain ./, as this is filtered out @@ -3367,7 +3368,7 @@ NTSTATUS get_relative_fid_filename(connection_struct *conn, goto out; } } else { - size_t dir_name_len = strlen(dir_fsp->fsp_name); + size_t dir_name_len = strlen(dir_fsp->fsp_name->base_name); /* * Copy in the base directory name. @@ -3379,7 +3380,7 @@ NTSTATUS get_relative_fid_filename(connection_struct *conn, status = NT_STATUS_NO_MEMORY; goto out; } - memcpy(parent_fname, dir_fsp->fsp_name, + memcpy(parent_fname, dir_fsp->fsp_name->base_name, dir_name_len+1); /* @@ -3463,16 +3464,9 @@ NTSTATUS create_file_default(connection_struct *conn, */ if (is_ntfs_stream_smb_fname(smb_fname)) { - char *fname = NULL; enum FAKE_FILE_TYPE fake_file_type; - status = get_full_smb_filename(talloc_tos(), smb_fname, - &fname); - if (!NT_STATUS_IS_OK(status)) { - goto fail; - } - - fake_file_type = is_fake_file(fname); + fake_file_type = is_fake_file(smb_fname); if (fake_file_type != FAKE_FILE_TYPE_NONE) { @@ -3488,9 +3482,8 @@ NTSTATUS create_file_default(connection_struct *conn, * close it */ status = open_fake_file(req, conn, req->vuid, - fake_file_type, fname, + fake_file_type, smb_fname, access_mask, &fsp); - TALLOC_FREE(fname); if (!NT_STATUS_IS_OK(status)) { goto fail; } @@ -3498,7 +3491,6 @@ NTSTATUS create_file_default(connection_struct *conn, ZERO_STRUCT(smb_fname->st); goto done; } - TALLOC_FREE(fname); if (!(conn->fs_capabilities & FILE_NAMED_STREAMS)) { status = NT_STATUS_OBJECT_NAME_NOT_FOUND; diff --git a/source3/smbd/oplock.c b/source3/smbd/oplock.c index e9b2a6cf95..dd8d5372fb 100644 --- a/source3/smbd/oplock.c +++ b/source3/smbd/oplock.c @@ -81,7 +81,7 @@ bool set_file_oplock(files_struct *fsp, int oplock_type) DEBUG(5,("set_file_oplock: granted oplock on file %s, %s/%lu, " "tv_sec = %x, tv_usec = %x\n", - fsp->fsp_name, file_id_string_tos(&fsp->file_id), + fsp_str_dbg(fsp), file_id_string_tos(&fsp->file_id), fsp->fh->gen_id, (int)fsp->open_time.tv_sec, (int)fsp->open_time.tv_usec )); @@ -158,14 +158,15 @@ bool remove_oplock(files_struct *fsp) NULL); if (lck == NULL) { DEBUG(0,("remove_oplock: failed to lock share entry for " - "file %s\n", fsp->fsp_name )); + "file %s\n", fsp_str_dbg(fsp))); return False; } ret = remove_share_oplock(lck, fsp); if (!ret) { DEBUG(0,("remove_oplock: failed to remove share oplock for " "file %s fnum %d, %s\n", - fsp->fsp_name, fsp->fnum, file_id_string_tos(&fsp->file_id))); + fsp_str_dbg(fsp), fsp->fnum, + file_id_string_tos(&fsp->file_id))); } release_file_oplock(fsp); TALLOC_FREE(lck); @@ -184,14 +185,15 @@ bool downgrade_oplock(files_struct *fsp) NULL); if (lck == NULL) { DEBUG(0,("downgrade_oplock: failed to lock share entry for " - "file %s\n", fsp->fsp_name )); + "file %s\n", fsp_str_dbg(fsp))); return False; } ret = downgrade_share_oplock(lck, fsp); if (!ret) { DEBUG(0,("downgrade_oplock: failed to downgrade share oplock " "for file %s fnum %d, file_id %s\n", - fsp->fsp_name, fsp->fnum, file_id_string_tos(&fsp->file_id))); + fsp_str_dbg(fsp), fsp->fnum, + file_id_string_tos(&fsp->file_id))); } downgrade_file_oplock(fsp); @@ -294,7 +296,8 @@ static files_struct *initial_break_processing(struct file_id id, unsigned long f if(fsp->oplock_type == NO_OPLOCK) { if( DEBUGLVL( 3 ) ) { - dbgtext( "initial_break_processing: file %s ", fsp->fsp_name ); + dbgtext( "initial_break_processing: file %s ", + fsp_str_dbg(fsp)); dbgtext( "(file_id = %s gen_id = %lu) has no oplock.\n", file_id_string_tos(&id), fsp->fh->gen_id ); dbgtext( "Allowing break to succeed regardless.\n" ); @@ -314,7 +317,8 @@ static void oplock_timeout_handler(struct event_context *ctx, /* Remove the timed event handler. */ TALLOC_FREE(fsp->oplock_timeout); - DEBUG(0, ("Oplock break failed for file %s -- replying anyway\n", fsp->fsp_name)); + DEBUG(0, ("Oplock break failed for file %s -- replying anyway\n", + fsp_str_dbg(fsp))); global_client_failed_oplock_break = True; remove_oplock(fsp); reply_to_oplock_break_requests(fsp); @@ -375,7 +379,7 @@ void break_level2_to_none_async(files_struct *fsp) DEBUG(10,("process_oplock_async_level2_break_message: sending break " "to none message for fid %d, file %s\n", fsp->fnum, - fsp->fsp_name)); + fsp_str_dbg(fsp))); /* Now send a break to none message to our client. */ break_msg = new_break_smb_message(NULL, fsp, OPLOCKLEVEL_NONE); @@ -506,7 +510,7 @@ static void process_oplock_break_message(struct messaging_context *msg_ctx, !EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) { DEBUG(3, ("Already downgraded oplock on %s: %s\n", file_id_string_tos(&fsp->file_id), - fsp->fsp_name)); + fsp_str_dbg(fsp))); /* We just send the same message back. */ messaging_send_buf(msg_ctx, src, MSG_SMB_BREAK_RESPONSE, (uint8 *)data->data, @@ -740,7 +744,7 @@ static void contend_level2_oplocks_begin_default(files_struct *fsp, NULL); if (lck == NULL) { DEBUG(0,("release_level_2_oplocks_on_change: failed to lock " - "share mode entry for file %s.\n", fsp->fsp_name )); + "share mode entry for file %s.\n", fsp_str_dbg(fsp))); return; } diff --git a/source3/smbd/oplock_irix.c b/source3/smbd/oplock_irix.c index 89b8e0f7b5..dd32177988 100644 --- a/source3/smbd/oplock_irix.c +++ b/source3/smbd/oplock_irix.c @@ -212,7 +212,8 @@ static bool irix_set_kernel_oplock(struct kernel_oplocks *_ctx, DEBUG(0,("irix_set_kernel_oplock: Unable to get " "kernel oplock on file %s, file_id %s " "gen_id = %ul. Error was %s\n", - fsp->fsp_name, file_id_string_tos(&fsp->file_id), + fsp_str_dbg(fsp), + file_id_string_tos(&fsp->file_id), fsp->fh->gen_id, strerror(errno) )); } else { @@ -220,7 +221,7 @@ static bool irix_set_kernel_oplock(struct kernel_oplocks *_ctx, "file %s, fd = %d, file_id = %s, " "gen_id = %ul. Another process had the file " "open.\n", - fsp->fsp_name, fsp->fh->fd, + fsp_str_dbg(fsp), fsp->fh->fd, file_id_string_tos(&fsp->file_id), fsp->fh->gen_id )); } @@ -229,7 +230,7 @@ static bool irix_set_kernel_oplock(struct kernel_oplocks *_ctx, DEBUG(10,("irix_set_kernel_oplock: got kernel oplock on file %s, file_id = %s " "gen_id = %ul\n", - fsp->fsp_name, file_id_string_tos(&fsp->file_id), + fsp_str_dbg(fsp), file_id_string_tos(&fsp->file_id), fsp->fh->gen_id)); return True; @@ -250,7 +251,8 @@ static void irix_release_kernel_oplock(struct kernel_oplocks *_ctx, int state = sys_fcntl_long(fsp->fh->fd, F_OPLKACK, -1); dbgtext("irix_release_kernel_oplock: file %s, file_id = %s" "gen_id = %ul, has kernel oplock state " - "of %x.\n", fsp->fsp_name, file_id_string_tos(&fsp->file_id), + "of %x.\n", fsp_str_dbg(fsp), + file_id_string_tos(&fsp->file_id), fsp->fh->gen_id, state ); } @@ -263,7 +265,8 @@ static void irix_release_kernel_oplock(struct kernel_oplocks *_ctx, "removing kernel oplock on file " ); dbgtext("%s, file_id = %s gen_id = %ul. " "Error was %s\n", - fsp->fsp_name, file_id_string_tos(&fsp->file_id), + fsp_str_dbg(fsp), + file_id_string_tos(&fsp->file_id), fsp->fh->gen_id, strerror(errno) ); } diff --git a/source3/smbd/oplock_linux.c b/source3/smbd/oplock_linux.c index 273fbfdc01..b4a5495e4b 100644 --- a/source3/smbd/oplock_linux.c +++ b/source3/smbd/oplock_linux.c @@ -111,7 +111,7 @@ static bool linux_set_kernel_oplock(struct kernel_oplocks *ctx, if ( SMB_VFS_LINUX_SETLEASE(fsp, F_WRLCK) == -1) { DEBUG(3,("linux_set_kernel_oplock: Refused oplock on file %s, " "fd = %d, file_id = %s. (%s)\n", - fsp->fsp_name, fsp->fh->fd, + fsp_str_dbg(fsp), fsp->fh->fd, file_id_string_tos(&fsp->file_id), strerror(errno))); return False; @@ -119,7 +119,7 @@ static bool linux_set_kernel_oplock(struct kernel_oplocks *ctx, DEBUG(3,("linux_set_kernel_oplock: got kernel oplock on file %s, " "file_id = %s gen_id = %lu\n", - fsp->fsp_name, file_id_string_tos(&fsp->file_id), + fsp_str_dbg(fsp), file_id_string_tos(&fsp->file_id), fsp->fh->gen_id)); return True; @@ -140,7 +140,8 @@ static void linux_release_kernel_oplock(struct kernel_oplocks *ctx, int state = fcntl(fsp->fh->fd, F_GETLEASE, 0); dbgtext("linux_release_kernel_oplock: file %s, file_id = %s " "gen_id = %lu has kernel oplock state " - "of %x.\n", fsp->fsp_name, file_id_string_tos(&fsp->file_id), + "of %x.\n", fsp_str_dbg(fsp), + file_id_string_tos(&fsp->file_id), fsp->fh->gen_id, state ); } @@ -152,7 +153,7 @@ static void linux_release_kernel_oplock(struct kernel_oplocks *ctx, dbgtext("linux_release_kernel_oplock: Error when " "removing kernel oplock on file " ); dbgtext("%s, file_id = %s, gen_id = %lu. " - "Error was %s\n", fsp->fsp_name, + "Error was %s\n", fsp_str_dbg(fsp), file_id_string_tos(&fsp->file_id), fsp->fh->gen_id, strerror(errno) ); } diff --git a/source3/smbd/oplock_onefs.c b/source3/smbd/oplock_onefs.c index d359f9c6f2..a73100abdf 100644 --- a/source3/smbd/oplock_onefs.c +++ b/source3/smbd/oplock_onefs.c @@ -60,29 +60,30 @@ struct onefs_callback_record { struct onefs_callback_record *callback_recs; /** - * Convert a onefs_callback_record to a string. + * Convert a onefs_callback_record to a debug string using the dbg_ctx(). */ -static char *onefs_callback_record_str_static(const struct onefs_callback_record *r) +const char *onefs_cb_record_str_dbg(const struct onefs_callback_record *r) { - static fstring result; + char *result; if (r == NULL) { - fstrcpy(result, "NULL callback record"); + result = talloc_strdup(dbg_ctx(), "NULL callback record"); return result; } switch (r->state) { case ONEFS_OPEN_FILE: - fstr_sprintf(result, "cb record %llu for file %s", - r->id, r->data.fsp->fsp_name); - break; + result = talloc_asprintf(dbg_ctx(), "cb record %llu for file " + "%s", r->id, + fsp_str_dbg(r->data.fsp)); case ONEFS_WAITING_FOR_OPLOCK: - fstr_sprintf(result, "cb record %llu for pending mid %d", - r->id, (int)r->data.mid); + result = talloc_asprintf(dbg_ctx(), "cb record %llu for " + "pending mid %d", r->id, + (int)r->data.mid); break; default: - fstr_sprintf(result, "cb record %llu unknown state %d", - r->id, r->state); + result = talloc_asprintf(dbg_ctx(), "cb record %llu unknown " + "state %d", r->id, r->state); break; } @@ -102,7 +103,7 @@ static void debug_cb_records(const char *fn) DEBUG(10, ("cb records (%s):\n", fn)); for (rec = callback_recs; rec; rec = rec->next) { - DEBUGADD(10, ("%s\n", onefs_callback_record_str_static(rec))); + DEBUGADD(10, ("%s\n", onefs_cb_record_dbg_str(rec))); } } @@ -127,7 +128,7 @@ static struct onefs_callback_record *onefs_find_cb(uint64_t id, for (rec = callback_recs; rec; rec = rec->next) { if (rec->id == id) { DEBUG(10, ("found %s\n", - onefs_callback_record_str_static(rec))); + onefs_cb_record_dbg_str(rec))); break; } } @@ -139,7 +140,7 @@ static struct onefs_callback_record *onefs_find_cb(uint64_t id, if (rec->state != expected_state) { DEBUG(0, ("Expected cb type %d, got %s", expected_state, - onefs_callback_record_str_static(rec))); + onefs_cb_record_dbg_str(rec))); SMB_ASSERT(0); return NULL; } @@ -299,7 +300,7 @@ static void oplock_break_to_none_handler(uint64_t id) } DEBUG(10, ("oplock_break_to_none_handler called for file %s\n", - cb->data.fsp->fsp_name)); + cb->data.fsp_str_dbg(fsp))); init_share_mode_entry(&sme, cb, FORCE_OPLOCK_BREAK_TO_NONE); share_mode_entry_to_message(msg, &sme); @@ -336,7 +337,7 @@ static void oplock_break_to_level_two_handler(uint64_t id) } DEBUG(10, ("oplock_break_to_level_two_handler called for file %s\n", - cb->data.fsp->fsp_name)); + cb->data.fsp_str_dbg(fsp))); init_share_mode_entry(&sme, cb, LEVEL_II_OPLOCK); share_mode_entry_to_message(msg, &sme); @@ -377,7 +378,7 @@ static void oplock_revoked_handler(uint64_t id) SMB_ASSERT(fsp->oplock_timeout == NULL); DEBUG(0,("Level 1 oplock break failed for file %s. Forcefully " - "revoking oplock\n", fsp->fsp_name)); + "revoking oplock\n", fsp_str_dbg(fsp))); global_client_failed_oplock_break = True; remove_oplock(fsp); @@ -413,7 +414,7 @@ static void semlock_available_handler(uint64_t id) char *msg; if (asprintf(&msg, "Semlock available on an open that wasn't " "deferred: %s\n", - onefs_callback_record_str_static(cb)) != -1) { + onefs_cb_record_dbg_str(cb)) != -1) { smb_panic(msg); } smb_panic("Semlock available on an open that wasn't " @@ -457,7 +458,7 @@ static void semlock_async_failure_handler(uint64_t id) char *msg; if (asprintf(&msg, "Semlock failure on an open that wasn't " "deferred: %s\n", - onefs_callback_record_str_static(cb)) != -1) { + onefs_cb_record_dbg_str(cb)) != -1) { smb_panic(msg); } smb_panic("Semlock failure on an open that wasn't deferred\n"); @@ -501,7 +502,7 @@ static void onefs_release_kernel_oplock(struct kernel_oplocks *_ctx, enum oplock_type oplock = onefs_samba_oplock_to_oplock(oplock_type); DEBUG(10, ("onefs_release_kernel_oplock: Releasing %s to type %s\n", - fsp->fsp_name, onefs_oplock_str(oplock))); + fsp_str_dbg(fsp), onefs_oplock_str(oplock))); if (fsp->fh->fd == -1) { DEBUG(1, ("no fd\n")); diff --git a/source3/smbd/password.c b/source3/smbd/password.c index 928ef0169e..b1a749736d 100644 --- a/source3/smbd/password.c +++ b/source3/smbd/password.c @@ -428,27 +428,30 @@ bool user_in_netgroup(struct smbd_server_connection *sconn, if (innetgr(ngname, NULL, user, sconn->smb1.sessions.my_yp_domain)) { DEBUG(5,("user_in_netgroup: Found\n")); return true; - } else { + } - /* - * Ok, innetgr is case sensitive. Try once more with lowercase - * just in case. Attempt to fix #703. JRA. - */ + /* + * Ok, innetgr is case sensitive. Try once more with lowercase + * just in case. Attempt to fix #703. JRA. + */ + fstrcpy(lowercase_user, user); + strlower_m(lowercase_user); - fstrcpy(lowercase_user, user); - strlower_m(lowercase_user); + if (strcmp(user,lowercase_user) == 0) { + /* user name was already lower case! */ + return false; + } - DEBUG(5,("looking for user %s of domain %s in netgroup %s\n", - lowercase_user, - sconn->smb1.sessions.my_yp_domain? - sconn->smb1.sessions.my_yp_domain:"(ANY)", - ngname)); + DEBUG(5,("looking for user %s of domain %s in netgroup %s\n", + lowercase_user, + sconn->smb1.sessions.my_yp_domain? + sconn->smb1.sessions.my_yp_domain:"(ANY)", + ngname)); - if (innetgr(ngname, NULL, lowercase_user, - sconn->smb1.sessions.my_yp_domain)) { - DEBUG(5,("user_in_netgroup: Found\n")); - return true; - } + if (innetgr(ngname, NULL, lowercase_user, + sconn->smb1.sessions.my_yp_domain)) { + DEBUG(5,("user_in_netgroup: Found\n")); + return true; } #endif /* HAVE_NETGROUP */ return false; diff --git a/source3/smbd/pipes.c b/source3/smbd/pipes.c index 7ae7435646..091db09987 100644 --- a/source3/smbd/pipes.c +++ b/source3/smbd/pipes.c @@ -37,6 +37,7 @@ NTSTATUS open_np_file(struct smb_request *smb_req, const char *name, { struct connection_struct *conn = smb_req->conn; struct files_struct *fsp; + struct smb_filename *smb_fname = NULL; NTSTATUS status; status = file_new(smb_req, conn, &fsp); @@ -50,7 +51,19 @@ NTSTATUS open_np_file(struct smb_request *smb_req, const char *name, fsp->vuid = smb_req->vuid; fsp->can_lock = false; fsp->access_mask = FILE_READ_DATA | FILE_WRITE_DATA; - string_set(&fsp->fsp_name, name); + + status = create_synthetic_smb_fname(talloc_tos(), name, NULL, NULL, + &smb_fname); + if (!NT_STATUS_IS_OK(status)) { + file_free(smb_req, fsp); + return status; + } + status = fsp_set_smb_fname(fsp, smb_fname); + TALLOC_FREE(smb_fname); + if (!NT_STATUS_IS_OK(status)) { + file_free(smb_req, fsp); + return status; + } status = np_open(NULL, name, conn->client_address, conn->server_info, &fsp->fake_file_handle); @@ -179,7 +192,7 @@ void reply_pipe_write(struct smb_request *req) data = req->buf + 3; DEBUG(6, ("reply_pipe_write: %x name: %s len: %d\n", (int)fsp->fnum, - fsp->fsp_name, (int)state->numtowrite)); + fsp_str_dbg(fsp), (int)state->numtowrite)); subreq = np_write_send(state, smbd_event_context(), fsp->fake_file_handle, data, state->numtowrite); @@ -203,8 +216,14 @@ static void pipe_write_done(struct tevent_req *subreq) status = np_write_recv(subreq, &nwritten); TALLOC_FREE(subreq); - if ((nwritten == 0 && state->numtowrite != 0) || (nwritten < 0)) { - reply_unixerror(req, ERRDOS, ERRnoaccess); + if (nwritten < 0) { + reply_nterror(req, status); + goto send; + } + + /* Looks bogus to me now. Needs to be removed ? JRA. */ + if ((nwritten == 0 && state->numtowrite != 0)) { + reply_doserror(req, ERRDOS, ERRnoaccess); goto send; } @@ -269,7 +288,7 @@ void reply_pipe_write_and_X(struct smb_request *req) == (PIPE_START_MESSAGE|PIPE_RAW_MODE)); DEBUG(6, ("reply_pipe_write_and_X: %x name: %s len: %d\n", - (int)fsp->fnum, fsp->fsp_name, (int)state->numtowrite)); + (int)fsp->fnum, fsp_str_dbg(fsp), (int)state->numtowrite)); data = (uint8_t *)smb_base(req->inbuf) + smb_doff; @@ -283,7 +302,7 @@ void reply_pipe_write_and_X(struct smb_request *req) DEBUG(0,("reply_pipe_write_and_X: start of message " "set and not enough data sent.(%u)\n", (unsigned int)state->numtowrite )); - reply_unixerror(req, ERRDOS, ERRnoaccess); + reply_nterror(req, NT_STATUS_INVALID_PARAMETER); return; } @@ -313,8 +332,15 @@ static void pipe_write_andx_done(struct tevent_req *subreq) status = np_write_recv(subreq, &nwritten); TALLOC_FREE(subreq); - if (!NT_STATUS_IS_OK(status) || (nwritten != state->numtowrite)) { - reply_unixerror(req, ERRDOS,ERRnoaccess); + + if (!NT_STATUS_IS_OK(status)) { + reply_nterror(req, status); + goto done; + } + + /* Looks bogus to me now. Is this error message correct ? JRA. */ + if (nwritten != state->numtowrite) { + reply_doserror(req, ERRDOS,ERRnoaccess); goto done; } diff --git a/source3/smbd/posix_acls.c b/source3/smbd/posix_acls.c index 76eee9b56a..0a3b0dff75 100644 --- a/source3/smbd/posix_acls.c +++ b/source3/smbd/posix_acls.c @@ -256,15 +256,16 @@ static void store_inheritance_attributes(files_struct *fsp, ret = SMB_VFS_FSETXATTR(fsp, SAMBA_POSIX_INHERITANCE_EA_NAME, pai_buf, store_size, 0); } else { - ret = SMB_VFS_SETXATTR(fsp->conn,fsp->fsp_name, SAMBA_POSIX_INHERITANCE_EA_NAME, - pai_buf, store_size, 0); + ret = SMB_VFS_SETXATTR(fsp->conn, fsp->fsp_name->base_name, + SAMBA_POSIX_INHERITANCE_EA_NAME, + pai_buf, store_size, 0); } SAFE_FREE(pai_buf); DEBUG(10,("store_inheritance_attribute: type 0x%x for file %s\n", (unsigned int)sd_type, - fsp->fsp_name)); + fsp_str_dbg(fsp))); if (ret == -1 && !no_acl_syscall_error(errno)) { DEBUG(1,("store_inheritance_attribute: Error %s\n", strerror(errno) )); @@ -599,8 +600,10 @@ static struct pai_val *fload_inherited_info(files_struct *fsp) ret = SMB_VFS_FGETXATTR(fsp, SAMBA_POSIX_INHERITANCE_EA_NAME, pai_buf, pai_buf_size); } else { - ret = SMB_VFS_GETXATTR(fsp->conn,fsp->fsp_name,SAMBA_POSIX_INHERITANCE_EA_NAME, - pai_buf, pai_buf_size); + ret = SMB_VFS_GETXATTR(fsp->conn, + fsp->fsp_name->base_name, + SAMBA_POSIX_INHERITANCE_EA_NAME, + pai_buf, pai_buf_size); } if (ret == -1) { @@ -618,7 +621,8 @@ static struct pai_val *fload_inherited_info(files_struct *fsp) } } while (ret == -1); - DEBUG(10,("load_inherited_info: ret = %lu for file %s\n", (unsigned long)ret, fsp->fsp_name)); + DEBUG(10,("load_inherited_info: ret = %lu for file %s\n", + (unsigned long)ret, fsp_str_dbg(fsp))); if (ret == -1) { /* No attribute or not supported. */ @@ -637,8 +641,7 @@ static struct pai_val *fload_inherited_info(files_struct *fsp) if (paiv) { DEBUG(10,("load_inherited_info: ACL type is 0x%x for file %s\n", - (unsigned int)paiv->sd_type, - fsp->fsp_name)); + (unsigned int)paiv->sd_type, fsp_str_dbg(fsp))); } SAFE_FREE(pai_buf); @@ -1727,8 +1730,12 @@ static bool create_canon_ace_lists(files_struct *fsp, got_dir_allow = True; if ((current_ace->attr == DENY_ACE) && got_dir_allow) { - DEBUG(0,("create_canon_ace_lists: malformed ACL in inheritable ACL ! \ -Deny entry after Allow entry. Failing to set on file %s.\n", fsp->fsp_name )); + DEBUG(0,("create_canon_ace_lists: " + "malformed ACL in " + "inheritable ACL! Deny entry " + "after Allow entry. Failing " + "to set on file %s.\n", + fsp_str_dbg(fsp))); free_canon_ace_list(file_ace); free_canon_ace_list(dir_ace); return False; @@ -1785,8 +1792,10 @@ Deny entry after Allow entry. Failing to set on file %s.\n", fsp->fsp_name )); got_file_allow = True; if ((current_ace->attr == DENY_ACE) && got_file_allow) { - DEBUG(0,("create_canon_ace_lists: malformed ACL in file ACL ! \ -Deny entry after Allow entry. Failing to set on file %s.\n", fsp->fsp_name )); + DEBUG(0,("create_canon_ace_lists: malformed " + "ACL in file ACL ! Deny entry after " + "Allow entry. Failing to set on file " + "%s.\n", fsp_str_dbg(fsp))); free_canon_ace_list(file_ace); free_canon_ace_list(dir_ace); return False; @@ -2169,17 +2178,8 @@ static mode_t create_default_mode(files_struct *fsp, bool interitable_mode) mode_t mode; if (interitable_mode) { - struct smb_filename *smb_fname = NULL; - NTSTATUS status; - - status = create_synthetic_smb_fname_split(talloc_tos(), - fsp->fsp_name, NULL, - &smb_fname); - if (!NT_STATUS_IS_OK(status)) { - return 0; - } - mode = unix_mode(fsp->conn, FILE_ATTRIBUTE_ARCHIVE, smb_fname, - NULL); + mode = unix_mode(fsp->conn, FILE_ATTRIBUTE_ARCHIVE, + fsp->fsp_name, NULL); } else { mode = S_IRUSR; } @@ -2602,14 +2602,9 @@ static bool set_canon_ace_list(files_struct *fsp, SMB_ACL_TYPE_T the_acl_type = (default_ace ? SMB_ACL_TYPE_DEFAULT : SMB_ACL_TYPE_ACCESS); bool needs_mask = False; mode_t mask_perms = 0; - struct smb_filename *smb_fname = NULL; - NTSTATUS status; - status = create_synthetic_smb_fname_split(talloc_tos(), fsp->fsp_name, - psbuf, &smb_fname); - if (!NT_STATUS_IS_OK(status)) { - goto fail; - } + /* Use the psbuf that was passed in. */ + fsp->fsp_name->st = *psbuf; #if defined(POSIX_ACL_NEEDS_MASK) /* HP-UX always wants to have a mask (called "class" there). */ @@ -2767,7 +2762,7 @@ static bool set_canon_ace_list(files_struct *fsp, */ if(default_ace || fsp->is_directory || fsp->fh->fd == -1) { - if (SMB_VFS_SYS_ACL_SET_FILE(conn, smb_fname->base_name, + if (SMB_VFS_SYS_ACL_SET_FILE(conn, fsp->fsp_name->base_name, the_acl_type, the_acl) == -1) { /* * Some systems allow all the above calls and only fail with no ACL support @@ -2777,17 +2772,17 @@ static bool set_canon_ace_list(files_struct *fsp, *pacl_set_support = False; } - if (acl_group_override(conn, smb_fname)) { + if (acl_group_override(conn, fsp->fsp_name)) { int sret; DEBUG(5,("set_canon_ace_list: acl group " "control on and current user in file " "%s primary group.\n", - smb_fname_str_dbg(smb_fname))); + fsp_str_dbg(fsp))); become_root(); sret = SMB_VFS_SYS_ACL_SET_FILE(conn, - smb_fname->base_name, the_acl_type, + fsp->fsp_name->base_name, the_acl_type, the_acl); unbecome_root(); if (sret == 0) { @@ -2801,8 +2796,7 @@ static bool set_canon_ace_list(files_struct *fsp, "file %s (%s).\n", the_acl_type == SMB_ACL_TYPE_DEFAULT ? "directory default" : "file", - smb_fname_str_dbg(smb_fname), - strerror(errno))); + fsp_str_dbg(fsp), strerror(errno))); goto fail; } } @@ -2816,13 +2810,13 @@ static bool set_canon_ace_list(files_struct *fsp, *pacl_set_support = False; } - if (acl_group_override(conn, smb_fname)) { + if (acl_group_override(conn, fsp->fsp_name)) { int sret; DEBUG(5,("set_canon_ace_list: acl group " "control on and current user in file " "%s primary group.\n", - smb_fname_str_dbg(smb_fname))); + fsp_str_dbg(fsp))); become_root(); sret = SMB_VFS_SYS_ACL_SET_FD(fsp, the_acl); @@ -2836,8 +2830,7 @@ static bool set_canon_ace_list(files_struct *fsp, DEBUG(2,("set_canon_ace_list: " "sys_acl_set_file failed for file %s " "(%s).\n", - smb_fname_str_dbg(smb_fname), - strerror(errno) )); + fsp_str_dbg(fsp), strerror(errno))); goto fail; } } @@ -2850,7 +2843,6 @@ static bool set_canon_ace_list(files_struct *fsp, if (the_acl != NULL) { SMB_VFS_SYS_ACL_FREE_ACL(conn, the_acl); } - TALLOC_FREE(smb_fname); return ret; } @@ -2906,8 +2898,9 @@ static bool convert_canon_ace_to_posix_perms( files_struct *fsp, canon_ace *file mode_t or_bits; if (ace_count != 3) { - DEBUG(3,("convert_canon_ace_to_posix_perms: Too many ACE entries for file %s to convert to \ -posix perms.\n", fsp->fsp_name )); + DEBUG(3,("convert_canon_ace_to_posix_perms: Too many ACE " + "entries for file %s to convert to posix perms.\n", + fsp_str_dbg(fsp))); return False; } @@ -2921,8 +2914,8 @@ posix perms.\n", fsp->fsp_name )); } if (!owner_ace || !group_ace || !other_ace) { - DEBUG(3,("convert_canon_ace_to_posix_perms: Can't get standard entries for file %s.\n", - fsp->fsp_name )); + DEBUG(3,("convert_canon_ace_to_posix_perms: Can't get " + "standard entries for file %s.\n", fsp_str_dbg(fsp))); return False; } @@ -2956,9 +2949,10 @@ posix perms.\n", fsp->fsp_name )); *posix_perms = (((*posix_perms) & and_bits)|or_bits); - DEBUG(10,("convert_canon_ace_to_posix_perms: converted u=%o,g=%o,w=%o to perm=0%o for file %s.\n", - (int)owner_ace->perms, (int)group_ace->perms, (int)other_ace->perms, (int)*posix_perms, - fsp->fsp_name )); + DEBUG(10,("convert_canon_ace_to_posix_perms: converted u=%o,g=%o,w=%o " + "to perm=0%o for file %s.\n", (int)owner_ace->perms, + (int)group_ace->perms, (int)other_ace->perms, + (int)*posix_perms, fsp_str_dbg(fsp))); return True; } @@ -3351,11 +3345,12 @@ NTSTATUS posix_fget_nt_acl(struct files_struct *fsp, uint32_t security_info, *ppdesc = NULL; - DEBUG(10,("posix_fget_nt_acl: called for file %s\n", fsp->fsp_name )); + DEBUG(10,("posix_fget_nt_acl: called for file %s\n", + fsp_str_dbg(fsp))); /* can it happen that fsp_name == NULL ? */ if (fsp->is_directory || fsp->fh->fd == -1) { - return posix_get_nt_acl(fsp->conn, fsp->fsp_name, + return posix_get_nt_acl(fsp->conn, fsp->fsp_name->base_name, security_info, ppdesc); } @@ -3369,40 +3364,53 @@ NTSTATUS posix_fget_nt_acl(struct files_struct *fsp, uint32_t security_info, pal = fload_inherited_info(fsp); - return posix_get_nt_acl_common(fsp->conn, fsp->fsp_name, &sbuf, pal, - posix_acl, NULL, security_info, ppdesc); + return posix_get_nt_acl_common(fsp->conn, fsp->fsp_name->base_name, + &sbuf, pal, posix_acl, NULL, + security_info, ppdesc); } NTSTATUS posix_get_nt_acl(struct connection_struct *conn, const char *name, uint32_t security_info, SEC_DESC **ppdesc) { - SMB_STRUCT_STAT sbuf; SMB_ACL_T posix_acl = NULL; SMB_ACL_T def_acl = NULL; struct pai_val *pal; + struct smb_filename *smb_fname = NULL; + NTSTATUS status; *ppdesc = NULL; DEBUG(10,("posix_get_nt_acl: called for file %s\n", name )); + status = create_synthetic_smb_fname(talloc_tos(), name, NULL, NULL, + &smb_fname); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + /* Get the stat struct for the owner info. */ - if(vfs_stat_smb_fname(conn, name, &sbuf) != 0) { - return map_nt_error_from_unix(errno); + if(SMB_VFS_STAT(conn, smb_fname) != 0) { + status = map_nt_error_from_unix(errno); + goto out; } /* Get the ACL from the path. */ posix_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, name, SMB_ACL_TYPE_ACCESS); /* If it's a directory get the default POSIX ACL. */ - if(S_ISDIR(sbuf.st_ex_mode)) { + if(S_ISDIR(smb_fname->st.st_ex_mode)) { def_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, name, SMB_ACL_TYPE_DEFAULT); def_acl = free_empty_sys_acl(conn, def_acl); } pal = load_inherited_info(conn, name); - return posix_get_nt_acl_common(conn, name, &sbuf, pal, posix_acl, - def_acl, security_info, ppdesc); + status = posix_get_nt_acl_common(conn, name, &smb_fname->st, pal, + posix_acl, def_acl, security_info, + ppdesc); + out: + TALLOC_FREE(smb_fname); + return status; } /**************************************************************************** @@ -3514,7 +3522,8 @@ NTSTATUS append_parent_acl(files_struct *fsp, return NT_STATUS_NO_MEMORY; } - if (!parent_dirname(mem_ctx, fsp->fsp_name, &parent_name, NULL)) { + if (!parent_dirname(mem_ctx, fsp->fsp_name->base_name, &parent_name, + NULL)) { return NT_STATUS_NO_MEMORY; } @@ -3596,7 +3605,7 @@ NTSTATUS append_parent_acl(files_struct *fsp, "ignoring non container " "inherit flags %u on ACE with sid %s " "from parent %s\n", - fsp->fsp_name, + fsp_str_dbg(fsp), (unsigned int)se->flags, sid_string_dbg(&se->trustee), parent_name)); @@ -3609,7 +3618,7 @@ NTSTATUS append_parent_acl(files_struct *fsp, "ignoring non object " "inherit flags %u on ACE with sid %s " "from parent %s\n", - fsp->fsp_name, + fsp_str_dbg(fsp), (unsigned int)se->flags, sid_string_dbg(&se->trustee), parent_name)); @@ -3633,7 +3642,7 @@ NTSTATUS append_parent_acl(files_struct *fsp, DEBUG(10,("append_parent_acl: path %s " "ignoring ACE with protected sid %s " "from parent %s\n", - fsp->fsp_name, + fsp_str_dbg(fsp), sid_string_dbg(&se->trustee), parent_name)); continue; @@ -3671,7 +3680,7 @@ NTSTATUS append_parent_acl(files_struct *fsp, DEBUG(10,("append_parent_acl: path %s " "inheriting ACE with sid %s " "from parent %s\n", - fsp->fsp_name, + fsp_str_dbg(fsp), sid_string_dbg(&se->trustee), parent_name)); } @@ -3707,21 +3716,13 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, const SEC_DESC bool set_acl_as_root = false; bool acl_set_support = false; bool ret = false; - struct smb_filename *smb_fname = NULL; - - status = create_synthetic_smb_fname_split(talloc_tos(), fsp->fsp_name, - NULL, &smb_fname); - if (!NT_STATUS_IS_OK(status)) { - goto out; - } DEBUG(10,("set_nt_acl: called for file %s\n", - smb_fname_str_dbg(smb_fname))); + fsp_str_dbg(fsp))); if (!CAN_WRITE(conn)) { DEBUG(10,("set acl rejected on read-only share\n")); - status = NT_STATUS_MEDIA_WRITE_PROTECTED; - goto out; + return NT_STATUS_MEDIA_WRITE_PROTECTED; } /* @@ -3729,19 +3730,17 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, const SEC_DESC */ if(fsp->is_directory || fsp->fh->fd == -1) { - if(SMB_VFS_STAT(fsp->conn, smb_fname) != 0) { - status = map_nt_error_from_unix(errno); - goto out; + if(SMB_VFS_STAT(fsp->conn, fsp->fsp_name) != 0) { + return map_nt_error_from_unix(errno); } } else { - if(SMB_VFS_FSTAT(fsp, &smb_fname->st) != 0) { - status = map_nt_error_from_unix(errno); - goto out; + if(SMB_VFS_FSTAT(fsp, &fsp->fsp_name->st) != 0) { + return map_nt_error_from_unix(errno); } } /* Save the original element we check against. */ - orig_mode = smb_fname->st.st_ex_mode; + orig_mode = fsp->fsp_name->st.st_ex_mode; /* * Unpack the user/group/world id's. @@ -3749,7 +3748,7 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, const SEC_DESC status = unpack_nt_owners( SNUM(conn), &user, &grp, security_info_sent, psd); if (!NT_STATUS_IS_OK(status)) { - goto out; + return status; } /* @@ -3758,24 +3757,22 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, const SEC_DESC * Noticed by Simo. */ - if (((user != (uid_t)-1) && (smb_fname->st.st_ex_uid != user)) || - (( grp != (gid_t)-1) && (smb_fname->st.st_ex_gid != grp))) { + if (((user != (uid_t)-1) && (fsp->fsp_name->st.st_ex_uid != user)) || + (( grp != (gid_t)-1) && (fsp->fsp_name->st.st_ex_gid != grp))) { DEBUG(3,("set_nt_acl: chown %s. uid = %u, gid = %u.\n", - smb_fname_str_dbg(smb_fname), (unsigned int)user, - (unsigned int)grp )); + fsp_str_dbg(fsp), (unsigned int)user, + (unsigned int)grp)); - if(try_chown(fsp->conn, smb_fname, user, grp) == -1) { + if(try_chown(fsp->conn, fsp->fsp_name, user, grp) == -1) { DEBUG(3,("set_nt_acl: chown %s, %u, %u failed. Error " - "= %s.\n", smb_fname_str_dbg(smb_fname), + "= %s.\n", fsp_str_dbg(fsp), (unsigned int)user, (unsigned int)grp, strerror(errno))); if (errno == EPERM) { - status = NT_STATUS_INVALID_OWNER; - goto out; + return NT_STATUS_INVALID_OWNER; } - status = map_nt_error_from_unix(errno); - goto out; + return map_nt_error_from_unix(errno); } /* @@ -3784,25 +3781,24 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, const SEC_DESC */ if(fsp->is_directory) { - if(SMB_VFS_STAT(fsp->conn, smb_fname) != 0) { - status = map_nt_error_from_unix(errno); - goto out; + if(SMB_VFS_STAT(fsp->conn, fsp->fsp_name) != 0) { + return map_nt_error_from_unix(errno); } } else { int sret; if(fsp->fh->fd == -1) - sret = SMB_VFS_STAT(fsp->conn, smb_fname); + sret = SMB_VFS_STAT(fsp->conn, fsp->fsp_name); else - sret = SMB_VFS_FSTAT(fsp, &smb_fname->st); + sret = SMB_VFS_FSTAT(fsp, &fsp->fsp_name->st); if(sret != 0) return map_nt_error_from_unix(errno); } /* Save the original element we check against. */ - orig_mode = smb_fname->st.st_ex_mode; + orig_mode = fsp->fsp_name->st.st_ex_mode; /* If we successfully chowned, we know we must * be able to set the acl, so do it as root. @@ -3810,24 +3806,22 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, const SEC_DESC set_acl_as_root = true; } - create_file_sids(&smb_fname->st, &file_owner_sid, &file_grp_sid); + create_file_sids(&fsp->fsp_name->st, &file_owner_sid, &file_grp_sid); - acl_perms = unpack_canon_ace(fsp, &smb_fname->st, &file_owner_sid, + acl_perms = unpack_canon_ace(fsp, &fsp->fsp_name->st, &file_owner_sid, &file_grp_sid, &file_ace_list, &dir_ace_list, security_info_sent, psd); /* Ignore W2K traverse DACL set. */ if (!file_ace_list && !dir_ace_list) { - status = NT_STATUS_OK; - goto out; + return NT_STATUS_OK; } if (!acl_perms) { DEBUG(3,("set_nt_acl: cannot set permissions\n")); free_canon_ace_list(file_ace_list); free_canon_ace_list(dir_ace_list); - status = NT_STATUS_ACCESS_DENIED; - goto out; + return NT_STATUS_ACCESS_DENIED; } /* @@ -3837,8 +3831,7 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, const SEC_DESC if(!(security_info_sent & DACL_SECURITY_INFORMATION) || (psd->dacl == NULL)) { free_canon_ace_list(file_ace_list); free_canon_ace_list(dir_ace_list); - status = NT_STATUS_OK; - goto out; + return NT_STATUS_OK; } /* @@ -3851,18 +3844,17 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, const SEC_DESC become_root(); } ret = set_canon_ace_list(fsp, file_ace_list, false, - &smb_fname->st, &acl_set_support); + &fsp->fsp_name->st, &acl_set_support); if (set_acl_as_root) { unbecome_root(); } if (acl_set_support && ret == false) { DEBUG(3,("set_nt_acl: failed to set file acl on file " - "%s (%s).\n", smb_fname_str_dbg(smb_fname), + "%s (%s).\n", fsp_str_dbg(fsp), strerror(errno))); free_canon_ace_list(file_ace_list); free_canon_ace_list(dir_ace_list); - status = map_nt_error_from_unix(errno); - goto out; + return map_nt_error_from_unix(errno); } } @@ -3872,7 +3864,7 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, const SEC_DESC become_root(); } ret = set_canon_ace_list(fsp, dir_ace_list, true, - &smb_fname->st, + &fsp->fsp_name->st, &acl_set_support); if (set_acl_as_root) { unbecome_root(); @@ -3880,12 +3872,10 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, const SEC_DESC if (ret == false) { DEBUG(3,("set_nt_acl: failed to set default " "acl on directory %s (%s).\n", - smb_fname_str_dbg(smb_fname), - strerror(errno) )); + fsp_str_dbg(fsp), strerror(errno))); free_canon_ace_list(file_ace_list); free_canon_ace_list(dir_ace_list); - status = map_nt_error_from_unix(errno); - goto out; + return map_nt_error_from_unix(errno); } } else { int sret = -1; @@ -3898,23 +3888,23 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, const SEC_DESC become_root(); } sret = SMB_VFS_SYS_ACL_DELETE_DEF_FILE(conn, - smb_fname->base_name); + fsp->fsp_name->base_name); if (set_acl_as_root) { unbecome_root(); } if (sret == -1) { - if (acl_group_override(conn, smb_fname)) { + if (acl_group_override(conn, fsp->fsp_name)) { DEBUG(5,("set_nt_acl: acl group " "control on and current user " "in file %s primary group. " "Override delete_def_acl\n", - smb_fname_str_dbg(smb_fname))); + fsp_str_dbg(fsp))); become_root(); sret = SMB_VFS_SYS_ACL_DELETE_DEF_FILE( conn, - smb_fname->base_name); + fsp->fsp_name->base_name); unbecome_root(); } @@ -3922,8 +3912,7 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, const SEC_DESC DEBUG(3,("set_nt_acl: sys_acl_delete_def_file failed (%s)\n", strerror(errno))); free_canon_ace_list(file_ace_list); free_canon_ace_list(dir_ace_list); - status = map_nt_error_from_unix(errno); - goto out; + return map_nt_error_from_unix(errno); } } } @@ -3954,52 +3943,48 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, const SEC_DESC free_canon_ace_list(dir_ace_list); DEBUG(3,("set_nt_acl: failed to convert file acl to " "posix permissions for file %s.\n", - smb_fname_str_dbg(smb_fname))); - status = NT_STATUS_ACCESS_DENIED; - goto out; + fsp_str_dbg(fsp))); + return NT_STATUS_ACCESS_DENIED; } if (orig_mode != posix_perms) { int sret = -1; DEBUG(3,("set_nt_acl: chmod %s. perms = 0%o.\n", - smb_fname_str_dbg(smb_fname), - (unsigned int)posix_perms)); + fsp_str_dbg(fsp), (unsigned int)posix_perms)); if (set_acl_as_root) { become_root(); } - sret = SMB_VFS_CHMOD(conn, smb_fname->base_name, + sret = SMB_VFS_CHMOD(conn, fsp->fsp_name->base_name, posix_perms); if (set_acl_as_root) { unbecome_root(); } if(sret == -1) { - if (acl_group_override(conn, smb_fname)) { + if (acl_group_override(conn, fsp->fsp_name)) { DEBUG(5,("set_nt_acl: acl group " "control on and current user " "in file %s primary group. " "Override chmod\n", - smb_fname_str_dbg(smb_fname))); + fsp_str_dbg(fsp))); become_root(); - sret = - SMB_VFS_CHMOD(conn, - smb_fname->base_name, - posix_perms); + sret = SMB_VFS_CHMOD(conn, + fsp->fsp_name->base_name, + posix_perms); unbecome_root(); } if (sret == -1) { DEBUG(3,("set_nt_acl: chmod %s, 0%o " "failed. Error = %s.\n", - smb_fname_str_dbg(smb_fname), + fsp_str_dbg(fsp), (unsigned int)posix_perms, strerror(errno))); free_canon_ace_list(file_ace_list); free_canon_ace_list(dir_ace_list); - status = map_nt_error_from_unix(errno); - goto out; + return map_nt_error_from_unix(errno); } } } @@ -4008,10 +3993,7 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, const SEC_DESC free_canon_ace_list(file_ace_list); free_canon_ace_list(dir_ace_list); - status = NT_STATUS_OK; - out: - TALLOC_FREE(smb_fname); - return status; + return NT_STATUS_OK; } /**************************************************************************** @@ -4614,6 +4596,7 @@ SEC_DESC *get_nt_acl_no_snum( TALLOC_CTX *ctx, const char *fname) connection_struct *conn; files_struct finfo; struct fd_handle fh; + NTSTATUS status; conn = TALLOC_ZERO_P(ctx, connection_struct); if (conn == NULL) { @@ -4644,16 +4627,24 @@ SEC_DESC *get_nt_acl_no_snum( TALLOC_CTX *ctx, const char *fname) finfo.conn = conn; finfo.fh = &fh; finfo.fh->fd = -1; - finfo.fsp_name = CONST_DISCARD(char *,fname); + + status = create_synthetic_smb_fname(talloc_tos(), fname, NULL, NULL, + &finfo.fsp_name); + if (!NT_STATUS_IS_OK(status)) { + conn_free_internal( conn ); + return NULL; + } if (!NT_STATUS_IS_OK(SMB_VFS_FGET_NT_ACL( &finfo, DACL_SECURITY_INFORMATION, &psd))) { DEBUG(0,("get_nt_acl_no_snum: get_nt_acl returned zero.\n")); + TALLOC_FREE(finfo.fsp_name); conn_free_internal( conn ); return NULL; } ret_sd = dup_sec_desc( ctx, psd ); + TALLOC_FREE(finfo.fsp_name); conn_free_internal( conn ); return ret_sd; diff --git a/source3/smbd/process.c b/source3/smbd/process.c index b26bc150db..c2065caf79 100644 --- a/source3/smbd/process.c +++ b/source3/smbd/process.c @@ -2015,11 +2015,6 @@ void smbd_process(void) TALLOC_CTX *frame = talloc_stackframe(); char remaddr[INET6_ADDRSTRLEN]; - smbd_server_conn = talloc_zero(smbd_event_context(), struct smbd_server_connection); - if (!smbd_server_conn) { - exit_server("failed to create smbd_server_connection"); - } - if (lp_maxprotocol() == PROTOCOL_SMB2 && lp_security() != SEC_SHARE) { smbd_server_conn->allow_smb2 = true; diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c index 1fd4e50ea6..76d32a2f98 100644 --- a/source3/smbd/reply.c +++ b/source3/smbd/reply.c @@ -856,6 +856,7 @@ void reply_tcon_and_X(struct smb_request *req) END_PROFILE(SMBtconX); + req->tid = conn->cnum; chain_reply(req); return; } @@ -993,8 +994,7 @@ void reply_checkpath(struct smb_request *req) conn, req->flags2 & FLAGS2_DFS_PATHNAMES, name, - &smb_fname, - NULL); + &smb_fname); if (!NT_STATUS_IS_OK(status)) { if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { @@ -1090,8 +1090,7 @@ void reply_getatr(struct smb_request *req) conn, req->flags2 & FLAGS2_DFS_PATHNAMES, fname, - &smb_fname, - 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, @@ -1106,7 +1105,7 @@ void reply_getatr(struct smb_request *req) DEBUG(3,("reply_getatr: stat of %s failed (%s)\n", smb_fname_str_dbg(smb_fname), strerror(errno))); - reply_unixerror(req, ERRDOS,ERRbadfile); + reply_nterror(req, map_nt_error_from_unix(errno)); goto out; } @@ -1192,8 +1191,7 @@ void reply_setatr(struct smb_request *req) conn, req->flags2 & FLAGS2_DFS_PATHNAMES, fname, - &smb_fname, - 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, @@ -1220,7 +1218,7 @@ void reply_setatr(struct smb_request *req) 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_unixerror(req, ERRDOS, ERRnoaccess); + reply_nterror(req, status); goto out; } @@ -1232,7 +1230,7 @@ void reply_setatr(struct smb_request *req) if (file_set_dosmode(conn, smb_fname, mode, NULL, false) != 0) { - reply_unixerror(req, ERRDOS, ERRnoaccess); + reply_nterror(req, map_nt_error_from_unix(errno)); goto out; } } @@ -1258,7 +1256,7 @@ void reply_dskattr(struct smb_request *req) START_PROFILE(SMBdskattr); if (get_dfree_info(conn,".",True,&bsize,&dfree,&dsize) == (uint64_t)-1) { - reply_unixerror(req, ERRHRD, ERRgeneral); + reply_nterror(req, map_nt_error_from_unix(errno)); END_PROFILE(SMBdskattr); return; } @@ -1342,6 +1340,7 @@ void reply_search(struct smb_request *req) char *path = NULL; const char *mask = NULL; char *directory = NULL; + struct smb_filename *smb_fname = NULL; char *fname = NULL; SMB_OFF_T size; uint32 mode; @@ -1366,14 +1365,12 @@ void reply_search(struct smb_request *req) if (req->wct < 2) { reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - END_PROFILE(SMBsearch); - return; + goto out; } if (lp_posix_pathnames()) { reply_unknown_new(req, req->cmd); - END_PROFILE(SMBsearch); - return; + goto out; } /* If we were called as SMBffirst then we must expect close. */ @@ -1389,8 +1386,7 @@ void reply_search(struct smb_request *req) &nt_status, &mask_contains_wcard); if (!NT_STATUS_IS_OK(nt_status)) { reply_nterror(req, nt_status); - END_PROFILE(SMBsearch); - return; + goto out; } p++; @@ -1400,8 +1396,6 @@ void reply_search(struct smb_request *req) /* dirtype &= ~aDIR; */ if (status_len == 0) { - struct smb_filename *smb_fname = NULL; - nt_status = resolve_dfspath_wcard(ctx, conn, req->flags2 & FLAGS2_DFS_PATHNAMES, path, @@ -1411,35 +1405,25 @@ void reply_search(struct smb_request *req) if (NT_STATUS_EQUAL(nt_status,NT_STATUS_PATH_NOT_COVERED)) { reply_botherror(req, NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath); - END_PROFILE(SMBsearch); - return; + goto out; } reply_nterror(req, nt_status); - END_PROFILE(SMBsearch); - return; + goto out; } nt_status = unix_convert(ctx, conn, path, &smb_fname, UCF_ALLOW_WCARD_LCOMP); if (!NT_STATUS_IS_OK(nt_status)) { reply_nterror(req, nt_status); - END_PROFILE(SMBsearch); - return; + goto out; } - nt_status = get_full_smb_filename(ctx, smb_fname, &directory); - TALLOC_FREE(smb_fname); - if (!NT_STATUS_IS_OK(nt_status)) { - reply_nterror(req, nt_status); - END_PROFILE(SMBsearch); - return; - } + directory = smb_fname->base_name; nt_status = check_name(conn, directory); if (!NT_STATUS_IS_OK(nt_status)) { reply_nterror(req, nt_status); - END_PROFILE(SMBsearch); - return; + goto out; } p = strrchr_m(directory,'/'); @@ -1454,8 +1438,7 @@ void reply_search(struct smb_request *req) if (!directory) { reply_nterror(req, NT_STATUS_NO_MEMORY); - END_PROFILE(SMBsearch); - return; + goto out; } memset((char *)status,'\0',21); @@ -1472,8 +1455,7 @@ void reply_search(struct smb_request *req) &conn->dirptr); if (!NT_STATUS_IS_OK(nt_status)) { reply_nterror(req, nt_status); - END_PROFILE(SMBsearch); - return; + goto out; } dptr_num = dptr_dnum(conn->dirptr); } else { @@ -1513,8 +1495,7 @@ void reply_search(struct smb_request *req) if (!make_dir_struct(ctx,buf,"???????????",volume_label(SNUM(conn)), 0,aVOLID,0,!allow_long_path_components)) { reply_nterror(req, NT_STATUS_NO_MEMORY); - END_PROFILE(SMBsearch); - return; + goto out; } dptr_fill(buf+12,dptr_num); if (dptr_zero(buf+12) && (status_len==0)) { @@ -1526,8 +1507,7 @@ void reply_search(struct smb_request *req) data_blob_const(buf, sizeof(buf))) == -1) { reply_nterror(req, NT_STATUS_NO_MEMORY); - END_PROFILE(SMBsearch); - return; + goto out; } } else { unsigned int i; @@ -1566,8 +1546,7 @@ void reply_search(struct smb_request *req) convert_timespec_to_time_t(date), !allow_long_path_components)) { reply_nterror(req, NT_STATUS_NO_MEMORY); - END_PROFILE(SMBsearch); - return; + goto out; } if (!dptr_fill(buf+12,dptr_num)) { break; @@ -1576,8 +1555,7 @@ void reply_search(struct smb_request *req) data_blob_const(buf, sizeof(buf))) == -1) { reply_nterror(req, NT_STATUS_NO_MEMORY); - END_PROFILE(SMBsearch); - return; + goto out; } numentries++; } @@ -1604,8 +1582,7 @@ void reply_search(struct smb_request *req) if ((numentries == 0) && !mask_contains_wcard) { reply_botherror(req, STATUS_NO_MORE_FILES, ERRDOS, ERRnofiles); - END_PROFILE(SMBsearch); - return; + goto out; } SSVAL(req->outbuf,smb_vwv0,numentries); @@ -1637,7 +1614,8 @@ void reply_search(struct smb_request *req) dirtype, numentries, maxentries )); - + out: + TALLOC_FREE(smb_fname); END_PROFILE(SMBsearch); return; } @@ -1746,8 +1724,7 @@ void reply_open(struct smb_request *req) conn, req->flags2 & FLAGS2_DFS_PATHNAMES, fname, - &smb_fname, - NULL); + &smb_fname); if (!NT_STATUS_IS_OK(status)) { if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { reply_botherror(req, @@ -1759,10 +1736,10 @@ void reply_open(struct smb_request *req) goto out; } - if (!map_open_params_to_ntcreate( - smb_fname->base_name, deny_mode, OPENX_FILE_EXISTS_OPEN, - &access_mask, &share_mode, &create_disposition, - &create_options)) { + if (!map_open_params_to_ntcreate(smb_fname, deny_mode, + OPENX_FILE_EXISTS_OPEN, &access_mask, + &share_mode, &create_disposition, + &create_options)) { reply_nterror(req, NT_STATUS_DOS(ERRDOS, ERRbadaccess)); goto out; } @@ -1811,7 +1788,8 @@ void reply_open(struct smb_request *req) mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime); if (fattr & aDIR) { - DEBUG(3,("attempt to open a directory %s\n",fsp->fsp_name)); + DEBUG(3,("attempt to open a directory %s\n", + fsp_str_dbg(fsp))); close_file(req, fsp, ERROR_CLOSE); reply_doserror(req, ERRDOS,ERRnoaccess); goto out; @@ -1916,8 +1894,7 @@ void reply_open_and_X(struct smb_request *req) conn, req->flags2 & FLAGS2_DFS_PATHNAMES, fname, - &smb_fname, - NULL); + &smb_fname); if (!NT_STATUS_IS_OK(status)) { if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { reply_botherror(req, @@ -1929,9 +1906,10 @@ void reply_open_and_X(struct smb_request *req) goto out; } - if (!map_open_params_to_ntcreate( - smb_fname->base_name, deny_mode, smb_ofun, &access_mask, - &share_mode, &create_disposition, &create_options)) { + if (!map_open_params_to_ntcreate(smb_fname, deny_mode, smb_ofun, + &access_mask, &share_mode, + &create_disposition, + &create_options)) { reply_nterror(req, NT_STATUS_DOS(ERRDOS, ERRbadaccess)); goto out; } @@ -2076,6 +2054,7 @@ void reply_ulogoffX(struct smb_request *req) DEBUG( 3, ( "ulogoffX vuid=%d\n", req->vuid ) ); END_PROFILE(SMBulogoffX); + req->vuid = UID_FIELD_INVALID; chain_reply(req); } @@ -2124,8 +2103,7 @@ void reply_mknew(struct smb_request *req) conn, req->flags2 & FLAGS2_DFS_PATHNAMES, fname, - &smb_fname, - NULL); + &smb_fname); if (!NT_STATUS_IS_OK(status)) { if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { reply_botherror(req, @@ -2257,8 +2235,7 @@ void reply_ctemp(struct smb_request *req) status = filename_convert(ctx, conn, req->flags2 & FLAGS2_DFS_PATHNAMES, fname, - &smb_fname, - 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, @@ -2271,7 +2248,7 @@ void reply_ctemp(struct smb_request *req) tmpfd = mkstemp(smb_fname->base_name); if (tmpfd == -1) { - reply_unixerror(req, ERRDOS, ERRnoaccess); + reply_nterror(req, map_nt_error_from_unix(errno)); goto out; } @@ -2311,9 +2288,9 @@ void reply_ctemp(struct smb_request *req) SSVAL(req->outbuf,smb_vwv0,fsp->fnum); /* the returned filename is relative to the directory */ - s = strrchr_m(fsp->fsp_name, '/'); + s = strrchr_m(fsp->fsp_name->base_name, '/'); if (!s) { - s = fsp->fsp_name; + s = fsp->fsp_name->base_name; } else { s++; } @@ -2339,8 +2316,8 @@ void reply_ctemp(struct smb_request *req) CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED); } - DEBUG( 2, ( "reply_ctemp: created temp file %s\n", fsp->fsp_name ) ); - DEBUG( 3, ( "reply_ctemp %s fd=%d umode=0%o\n", fsp->fsp_name, + DEBUG(2, ("reply_ctemp: created temp file %s\n", fsp_str_dbg(fsp))); + DEBUG(3, ("reply_ctemp %s fd=%d umode=0%o\n", fsp_str_dbg(fsp), fsp->fh->fd, (unsigned int)smb_fname->st.st_ex_mode)); out: TALLOC_FREE(smb_fname); @@ -2355,22 +2332,13 @@ void reply_ctemp(struct smb_request *req) static NTSTATUS can_rename(connection_struct *conn, files_struct *fsp, uint16 dirtype, SMB_STRUCT_STAT *pst) { - struct smb_filename *smb_fname = NULL; - NTSTATUS status; uint32 fmode; if (!CAN_WRITE(conn)) { return NT_STATUS_MEDIA_WRITE_PROTECTED; } - status = create_synthetic_smb_fname_split(talloc_tos(), fsp->fsp_name, - pst, &smb_fname); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - fmode = dos_mode(conn, smb_fname); - TALLOC_FREE(smb_fname); + fmode = dos_mode(conn, fsp->fsp_name); if ((fmode & ~dirtype) & (aHIDDEN | aSYSTEM)) { return NT_STATUS_NO_SUCH_FILE; } @@ -2646,18 +2614,23 @@ NTSTATUS unlink_internals(connection_struct *conn, struct smb_request *req, while ((dname = ReadDirName(dir_hnd, &offset, &smb_fname->st))) { + TALLOC_CTX *frame = talloc_stackframe(); + if (!is_visible_file(conn, fname_dir, dname, &smb_fname->st, true)) { + TALLOC_FREE(frame); continue; } /* Quick check for "." and ".." */ if (ISDOT(dname) || ISDOTDOT(dname)) { + TALLOC_FREE(frame); continue; } if(!mask_match(dname, fname_mask, conn->case_sensitive)) { + TALLOC_FREE(frame); continue; } @@ -2669,23 +2642,28 @@ NTSTATUS unlink_internals(connection_struct *conn, struct smb_request *req, if (!smb_fname->base_name) { TALLOC_FREE(dir_hnd); status = NT_STATUS_NO_MEMORY; + TALLOC_FREE(frame); goto out; } status = check_name(conn, smb_fname->base_name); if (!NT_STATUS_IS_OK(status)) { TALLOC_FREE(dir_hnd); + TALLOC_FREE(frame); goto out; } status = do_unlink(conn, req, smb_fname, dirtype); if (!NT_STATUS_IS_OK(status)) { + TALLOC_FREE(frame); continue; } count++; DEBUG(3,("unlink_internals: successful unlink [%s]\n", smb_fname->base_name)); + + TALLOC_FREE(frame); } TALLOC_FREE(dir_hnd); } @@ -2854,7 +2832,7 @@ static void sendfile_short_send(files_struct *fsp, if (nread < headersize) { DEBUG(0,("sendfile_short_send: sendfile failed to send " "header for file %s (%s). Terminating\n", - fsp->fsp_name, strerror(errno) )); + fsp_str_dbg(fsp), strerror(errno))); exit_server_cleanly("sendfile_short_send failed"); } @@ -2868,7 +2846,7 @@ static void sendfile_short_send(files_struct *fsp, } DEBUG(0,("sendfile_short_send: filling truncated file %s " - "with zeros !\n", fsp->fsp_name)); + "with zeros !\n", fsp_str_dbg(fsp))); while (nread < smb_maxcnt) { /* @@ -2963,15 +2941,19 @@ static void send_file_readbraw(connection_struct *conn, DEBUG(0,("send_file_readbraw: sendfile not available. Faking..\n")); if (fake_sendfile(fsp, startpos, nread) == -1) { - DEBUG(0,("send_file_readbraw: fake_sendfile failed for file %s (%s).\n", - fsp->fsp_name, strerror(errno) )); + DEBUG(0,("send_file_readbraw: " + "fake_sendfile failed for " + "file %s (%s).\n", + fsp_str_dbg(fsp), + strerror(errno))); exit_server_cleanly("send_file_readbraw fake_sendfile failed"); } return; } - DEBUG(0,("send_file_readbraw: sendfile failed for file %s (%s). Terminating\n", - fsp->fsp_name, strerror(errno) )); + DEBUG(0,("send_file_readbraw: sendfile failed for " + "file %s (%s). Terminating\n", + fsp_str_dbg(fsp), strerror(errno))); exit_server_cleanly("send_file_readbraw sendfile failed"); } else if (sendfile_read == 0) { /* @@ -2983,7 +2965,7 @@ static void send_file_readbraw(connection_struct *conn, */ DEBUG(3, ("send_file_readbraw: sendfile sent zero " "bytes falling back to the normal read: " - "%s\n", fsp->fsp_name)); + "%s\n", fsp_str_dbg(fsp))); goto normal_readbraw; } @@ -3269,7 +3251,7 @@ Returning short read of maximum allowed for compatibility with Windows 2000.\n", nread = read_file(fsp,data,startpos,numtoread); if (nread < 0) { - reply_unixerror(req, ERRDOS, ERRnoaccess); + reply_nterror(req, map_nt_error_from_unix(errno)); END_PROFILE(SMBlockread); return; } @@ -3363,7 +3345,7 @@ Returning short read of maximum allowed for compatibility with Windows 2000.\n", nread = read_file(fsp,data,startpos,numtoread); if (nread < 0) { - reply_unixerror(req, ERRDOS,ERRnoaccess); + reply_nterror(req, map_nt_error_from_unix(errno)); goto strict_unlock; } @@ -3425,9 +3407,10 @@ static void send_file_readX(connection_struct *conn, struct smb_request *req, SMB_STRUCT_STAT sbuf; ssize_t nread = -1; struct lock_struct lock; + int saved_errno = 0; if(SMB_VFS_FSTAT(fsp, &sbuf) == -1) { - reply_unixerror(req, ERRDOS, ERRnoaccess); + reply_nterror(req, map_nt_error_from_unix(errno)); return; } @@ -3494,8 +3477,11 @@ static void send_file_readX(connection_struct *conn, struct smb_request *req, nread = fake_sendfile(fsp, startpos, smb_maxcnt); if (nread == -1) { - DEBUG(0,("send_file_readX: fake_sendfile failed for file %s (%s).\n", - fsp->fsp_name, strerror(errno) )); + DEBUG(0,("send_file_readX: " + "fake_sendfile failed for " + "file %s (%s).\n", + fsp_str_dbg(fsp), + strerror(errno))); exit_server_cleanly("send_file_readX: fake_sendfile failed"); } DEBUG( 3, ( "send_file_readX: fake_sendfile fnum=%d max=%d nread=%d\n", @@ -3504,8 +3490,9 @@ static void send_file_readX(connection_struct *conn, struct smb_request *req, goto strict_unlock; } - DEBUG(0,("send_file_readX: sendfile failed for file %s (%s). Terminating\n", - fsp->fsp_name, strerror(errno) )); + DEBUG(0,("send_file_readX: sendfile failed for file " + "%s (%s). Terminating\n", fsp_str_dbg(fsp), + strerror(errno))); exit_server_cleanly("send_file_readX sendfile failed"); } else if (nread == 0) { /* @@ -3517,7 +3504,7 @@ static void send_file_readX(connection_struct *conn, struct smb_request *req, */ DEBUG(3, ("send_file_readX: sendfile sent zero bytes " "falling back to the normal read: %s\n", - fsp->fsp_name)); + fsp_str_dbg(fsp))); goto normal_read; } @@ -3547,14 +3534,16 @@ normal_read: /* Send out the header. */ if (write_data(smbd_server_fd(), (char *)headerbuf, sizeof(headerbuf)) != sizeof(headerbuf)) { - DEBUG(0,("send_file_readX: write_data failed for file %s (%s). Terminating\n", - fsp->fsp_name, strerror(errno) )); + DEBUG(0,("send_file_readX: write_data failed for file " + "%s (%s). Terminating\n", fsp_str_dbg(fsp), + strerror(errno))); exit_server_cleanly("send_file_readX sendfile failed"); } nread = fake_sendfile(fsp, startpos, smb_maxcnt); if (nread == -1) { - DEBUG(0,("send_file_readX: fake_sendfile failed for file %s (%s).\n", - fsp->fsp_name, strerror(errno) )); + DEBUG(0,("send_file_readX: fake_sendfile failed for " + "file %s (%s).\n", fsp_str_dbg(fsp), + strerror(errno))); exit_server_cleanly("send_file_readX: fake_sendfile failed"); } goto strict_unlock; @@ -3565,11 +3554,12 @@ nosendfile_read: reply_outbuf(req, 12, smb_maxcnt); nread = read_file(fsp, smb_buf(req->outbuf), startpos, smb_maxcnt); + saved_errno = errno; SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock); if (nread < 0) { - reply_unixerror(req, ERRDOS, ERRnoaccess); + reply_nterror(req, map_nt_error_from_unix(saved_errno)); return; } @@ -3810,7 +3800,7 @@ void reply_writebraw(struct smb_request *req) (int)nwritten, (int)write_through)); if (nwritten < (ssize_t)numtowrite) { - reply_unixerror(req, ERRHRD, ERRdiskfull); + reply_doserror(req, ERRHRD, ERRdiskfull); error_to_writebrawerr(req); goto strict_unlock; } @@ -3879,7 +3869,7 @@ void reply_writebraw(struct smb_request *req) nwritten = write_file(req,fsp,buf+4,startpos+nwritten,numtowrite); if (nwritten == -1) { TALLOC_FREE(buf); - reply_unixerror(req, ERRHRD, ERRdiskfull); + reply_nterror(req, map_nt_error_from_unix(errno)); error_to_writebrawerr(req); goto strict_unlock; } @@ -3900,7 +3890,7 @@ void reply_writebraw(struct smb_request *req) status = sync_file(conn, fsp, write_through); if (!NT_STATUS_IS_OK(status)) { DEBUG(5,("reply_writebraw: sync_file for %s returned %s\n", - fsp->fsp_name, nt_errstr(status) )); + fsp_str_dbg(fsp), nt_errstr(status))); reply_nterror(req, status); error_to_writebrawerr(req); goto strict_unlock; @@ -3958,6 +3948,7 @@ void reply_writeunlock(struct smb_request *req) NTSTATUS status = NT_STATUS_OK; files_struct *fsp; struct lock_struct lock; + int saved_errno = 0; START_PROFILE(SMBwriteunlock); @@ -4003,18 +3994,24 @@ void reply_writeunlock(struct smb_request *req) nwritten = 0; } else { nwritten = write_file(req,fsp,data,startpos,numtowrite); + saved_errno = errno; } status = sync_file(conn, fsp, False /* write through */); if (!NT_STATUS_IS_OK(status)) { DEBUG(5,("reply_writeunlock: sync_file for %s returned %s\n", - fsp->fsp_name, nt_errstr(status) )); + fsp_str_dbg(fsp), nt_errstr(status))); reply_nterror(req, status); goto strict_unlock; } - if(((nwritten < numtowrite) && (numtowrite != 0))||(nwritten < 0)) { - reply_unixerror(req, ERRHRD, ERRdiskfull); + if(nwritten < 0) { + reply_nterror(req, map_nt_error_from_unix(saved_errno)); + goto strict_unlock; + } + + if((nwritten < numtowrite) && (numtowrite != 0)) { + reply_doserror(req, ERRHRD, ERRdiskfull); goto strict_unlock; } @@ -4065,6 +4062,7 @@ void reply_write(struct smb_request *req) files_struct *fsp; struct lock_struct lock; NTSTATUS status; + int saved_errno = 0; START_PROFILE(SMBwrite); @@ -4136,13 +4134,18 @@ void reply_write(struct smb_request *req) status = sync_file(conn, fsp, False); if (!NT_STATUS_IS_OK(status)) { DEBUG(5,("reply_write: sync_file for %s returned %s\n", - fsp->fsp_name, nt_errstr(status) )); + fsp_str_dbg(fsp), nt_errstr(status))); reply_nterror(req, status); goto strict_unlock; } - if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) { - reply_unixerror(req, ERRHRD, ERRdiskfull); + if(nwritten < 0) { + reply_nterror(req, map_nt_error_from_unix(saved_errno)); + goto strict_unlock; + } + + if((nwritten == 0) && (numtowrite != 0)) { + reply_doserror(req, ERRHRD, ERRdiskfull); goto strict_unlock; } @@ -4389,8 +4392,13 @@ void reply_write_and_X(struct smb_request *req) nwritten = write_file(req,fsp,data,startpos,numtowrite); } - if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) { - reply_unixerror(req, ERRHRD, ERRdiskfull); + if(nwritten < 0) { + reply_nterror(req, map_nt_error_from_unix(errno)); + goto strict_unlock; + } + + if((nwritten == 0) && (numtowrite != 0)) { + reply_doserror(req, ERRHRD, ERRdiskfull); goto strict_unlock; } @@ -4409,7 +4417,7 @@ void reply_write_and_X(struct smb_request *req) status = sync_file(conn, fsp, write_through); if (!NT_STATUS_IS_OK(status)) { DEBUG(5,("reply_write_and_X: sync_file for %s returned %s\n", - fsp->fsp_name, nt_errstr(status) )); + fsp_str_dbg(fsp), nt_errstr(status))); reply_nterror(req, status); goto strict_unlock; } @@ -4484,8 +4492,8 @@ void reply_lseek(struct smb_request *req) SMB_STRUCT_STAT sbuf; if(SMB_VFS_FSTAT(fsp, &sbuf) == -1) { - reply_unixerror(req, ERRDOS, - ERRnoaccess); + reply_nterror(req, + map_nt_error_from_unix(errno)); END_PROFILE(SMBlseek); return; } @@ -4497,7 +4505,7 @@ void reply_lseek(struct smb_request *req) } if(res == -1) { - reply_unixerror(req, ERRDOS, ERRnoaccess); + reply_nterror(req, map_nt_error_from_unix(errno)); END_PROFILE(SMBlseek); return; } @@ -4545,7 +4553,7 @@ void reply_flush(struct smb_request *req) NTSTATUS status = sync_file(conn, fsp, True); if (!NT_STATUS_IS_OK(status)) { DEBUG(5,("reply_flush: sync_file for %s returned %s\n", - fsp->fsp_name, nt_errstr(status) )); + fsp_str_dbg(fsp), nt_errstr(status))); reply_nterror(req, status); END_PROFILE(SMBflush); return; @@ -4713,8 +4721,8 @@ void reply_writeclose(struct smb_request *req) */ if (numtowrite) { - DEBUG(3,("reply_writeclose: zero length write doesn't close file %s\n", - fsp->fsp_name )); + DEBUG(3,("reply_writeclose: zero length write doesn't close " + "file %s\n", fsp_str_dbg(fsp))); close_status = close_file(req, fsp, NORMAL_CLOSE); } @@ -5197,7 +5205,7 @@ void reply_printwrite(struct smb_request *req) data = (const char *)req->buf + 3; if (write_file(req,fsp,data,-1,numtowrite) != numtowrite) { - reply_unixerror(req, ERRHRD, ERRdiskfull); + reply_nterror(req, map_nt_error_from_unix(errno)); END_PROFILE(SMBsplwr); return; } @@ -5232,8 +5240,7 @@ void reply_mkdir(struct smb_request *req) status = filename_convert(ctx, conn, req->flags2 & FLAGS2_DFS_PATHNAMES, directory, - &smb_dname, - NULL); + &smb_dname); if (!NT_STATUS_IS_OK(status)) { if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { reply_botherror(req, NT_STATUS_PATH_NOT_COVERED, @@ -5540,8 +5547,7 @@ void reply_rmdir(struct smb_request *req) status = filename_convert(ctx, conn, req->flags2 & FLAGS2_DFS_PATHNAMES, directory, - &smb_dname, - NULL); + &smb_dname); if (!NT_STATUS_IS_OK(status)) { if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { reply_botherror(req, NT_STATUS_PATH_NOT_COVERED, @@ -5711,7 +5717,6 @@ static void rename_open_files(connection_struct *conn, { files_struct *fsp; bool did_rename = False; - char *fname_dst = NULL; NTSTATUS status; for(fsp = file_find_di_first(lck->id); fsp; @@ -5725,17 +5730,13 @@ static void rename_open_files(connection_struct *conn, } DEBUG(10, ("rename_open_files: renaming file fnum %d " "(file_id %s) from %s -> %s\n", fsp->fnum, - file_id_string_tos(&fsp->file_id), fsp->fsp_name, + file_id_string_tos(&fsp->file_id), fsp_str_dbg(fsp), smb_fname_str_dbg(smb_fname_dst))); - status = get_full_smb_filename(talloc_tos(), smb_fname_dst, - &fname_dst); - if (!NT_STATUS_IS_OK(status)) { - return; + status = fsp_set_smb_fname(fsp, smb_fname_dst); + if (NT_STATUS_IS_OK(status)) { + did_rename = True; } - string_set(&fsp->fsp_name, fname_dst); - did_rename = True; - TALLOC_FREE(fname_dst); } if (!did_rename) { @@ -5790,9 +5791,6 @@ static void notify_rename(connection_struct *conn, bool is_dir, { char *parent_dir_src = NULL; char *parent_dir_dst = NULL; - char *fname_src = NULL; - char *fname_dst = NULL; - NTSTATUS status; uint32 mask; mask = is_dir ? FILE_NOTIFY_CHANGE_DIR_NAME @@ -5805,24 +5803,17 @@ static void notify_rename(connection_struct *conn, bool is_dir, goto out; } - status = get_full_smb_filename(talloc_tos(), smb_fname_src, - &fname_src); - if (!NT_STATUS_IS_OK(status)) { - goto out; - } - status = get_full_smb_filename(talloc_tos(), smb_fname_dst, - &fname_dst); - if (!NT_STATUS_IS_OK(status)) { - goto out; - } - if (strcmp(parent_dir_src, parent_dir_dst) == 0) { - notify_fname(conn, NOTIFY_ACTION_OLD_NAME, mask, fname_src); - notify_fname(conn, NOTIFY_ACTION_NEW_NAME, mask, fname_dst); + notify_fname(conn, NOTIFY_ACTION_OLD_NAME, mask, + smb_fname_src->base_name); + notify_fname(conn, NOTIFY_ACTION_NEW_NAME, mask, + smb_fname_dst->base_name); } else { - notify_fname(conn, NOTIFY_ACTION_REMOVED, mask, fname_src); - notify_fname(conn, NOTIFY_ACTION_ADDED, mask, fname_dst); + notify_fname(conn, NOTIFY_ACTION_REMOVED, mask, + smb_fname_src->base_name); + notify_fname(conn, NOTIFY_ACTION_ADDED, mask, + smb_fname_dst->base_name); } /* this is a strange one. w2k3 gives an additional event for @@ -5832,13 +5823,11 @@ static void notify_rename(connection_struct *conn, bool is_dir, notify_fname(conn, NOTIFY_ACTION_MODIFIED, FILE_NOTIFY_CHANGE_ATTRIBUTES |FILE_NOTIFY_CHANGE_CREATION, - fname_dst); + smb_fname_dst->base_name); } out: TALLOC_FREE(parent_dir_src); TALLOC_FREE(parent_dir_dst); - TALLOC_FREE(fname_src); - TALLOC_FREE(fname_dst); } /**************************************************************************** @@ -5867,17 +5856,12 @@ NTSTATUS rename_internals_fsp(connection_struct *conn, } /* Make a copy of the src and dst smb_fname structs */ - status = copy_smb_filename(ctx, smb_fname_dst_in, &smb_fname_dst); + status = copy_smb_filename(ctx, fsp->fsp_name, &smb_fname_src); if (!NT_STATUS_IS_OK(status)) { goto out; } - /* - * This will be replaced with copy_smb_filename() when fsp->fsp_name - * is converted to store an smb_filename struct. - */ - status = create_synthetic_smb_fname_split(ctx, fsp->fsp_name, NULL, - &smb_fname_src); + status = copy_smb_filename(ctx, smb_fname_dst_in, &smb_fname_dst); if (!NT_STATUS_IS_OK(status)) { goto out; } @@ -6635,8 +6619,8 @@ NTSTATUS copy_file(TALLOC_CTX *ctx, if (!target_is_directory && count) { new_create_disposition = FILE_OPEN; } else { - if (!map_open_params_to_ntcreate(smb_fname_dst_tmp->base_name, - 0, ofun, NULL, NULL, + if (!map_open_params_to_ntcreate(smb_fname_dst_tmp, 0, ofun, + NULL, NULL, &new_create_disposition, NULL)) { status = NT_STATUS_INVALID_PARAMETER; @@ -6756,7 +6740,6 @@ void reply_copy(struct smb_request *req) const char *p; int count=0; int error = ERRnoaccess; - int err = 0; int tid2; int ofun; int flags; @@ -7059,13 +7042,6 @@ void reply_copy(struct smb_request *req) } if (count == 0) { - if(err) { - /* Error on close... */ - errno = err; - reply_unixerror(req, ERRHRD, ERRgeneral); - goto out; - } - reply_doserror(req, ERRDOS, error); goto out; } @@ -7223,6 +7199,205 @@ uint64_t get_lock_offset(const uint8_t *data, int data_offset, return offset; } +NTSTATUS smbd_do_locking(struct smb_request *req, + files_struct *fsp, + uint8_t type, + int32_t timeout, + uint16_t num_ulocks, + struct smbd_lock_element *ulocks, + uint16_t num_locks, + struct smbd_lock_element *locks, + bool *async) +{ + connection_struct *conn = req->conn; + int i; + NTSTATUS status = NT_STATUS_OK; + + *async = false; + + /* Data now points at the beginning of the list + of smb_unlkrng structs */ + for(i = 0; i < (int)num_ulocks; i++) { + struct smbd_lock_element *e = &ulocks[i]; + + DEBUG(10,("smbd_do_locking: unlock start=%.0f, len=%.0f for " + "pid %u, file %s\n", + (double)e->offset, + (double)e->count, + (unsigned int)e->smbpid, + fsp_str_dbg(fsp))); + + if (e->brltype != UNLOCK_LOCK) { + /* this can only happen with SMB2 */ + return NT_STATUS_INVALID_PARAMETER; + } + + status = do_unlock(smbd_messaging_context(), + fsp, + e->smbpid, + e->count, + e->offset, + WINDOWS_LOCK); + + DEBUG(10, ("smbd_do_locking: unlock returned %s\n", + nt_errstr(status))); + + if (!NT_STATUS_IS_OK(status)) { + return status; + } + } + + /* Setup the timeout in seconds. */ + + if (!lp_blocking_locks(SNUM(conn))) { + timeout = 0; + } + + /* Data now points at the beginning of the list + of smb_lkrng structs */ + + for(i = 0; i < (int)num_locks; i++) { + struct smbd_lock_element *e = &locks[i]; + + DEBUG(10,("smbd_do_locking: lock start=%.0f, len=%.0f for pid " + "%u, file %s timeout = %d\n", + (double)e->offset, + (double)e->count, + (unsigned int)e->smbpid, + fsp_str_dbg(fsp), + (int)timeout)); + + if (type & LOCKING_ANDX_CANCEL_LOCK) { + struct blocking_lock_record *blr = NULL; + + if (lp_blocking_locks(SNUM(conn))) { + + /* Schedule a message to ourselves to + remove the blocking lock record and + return the right error. */ + + blr = blocking_lock_cancel(fsp, + e->smbpid, + e->offset, + e->count, + WINDOWS_LOCK, + type, + NT_STATUS_FILE_LOCK_CONFLICT); + if (blr == NULL) { + return NT_STATUS_DOS( + ERRDOS, + ERRcancelviolation); + } + } + /* Remove a matching pending lock. */ + status = do_lock_cancel(fsp, + e->smbpid, + e->count, + e->offset, + WINDOWS_LOCK, + blr); + } else { + bool blocking_lock = timeout ? true : false; + bool defer_lock = false; + struct byte_range_lock *br_lck; + uint32_t block_smbpid; + + br_lck = do_lock(smbd_messaging_context(), + fsp, + e->smbpid, + e->count, + e->offset, + e->brltype, + WINDOWS_LOCK, + blocking_lock, + &status, + &block_smbpid, + NULL); + + if (br_lck && blocking_lock && ERROR_WAS_LOCK_DENIED(status)) { + /* Windows internal resolution for blocking locks seems + to be about 200ms... Don't wait for less than that. JRA. */ + if (timeout != -1 && timeout < lp_lock_spin_time()) { + timeout = lp_lock_spin_time(); + } + defer_lock = true; + } + + /* This heuristic seems to match W2K3 very well. If a + lock sent with timeout of zero would fail with NT_STATUS_FILE_LOCK_CONFLICT + it pretends we asked for a timeout of between 150 - 300 milliseconds as + far as I can tell. Replacement for do_lock_spin(). JRA. */ + + if (br_lck && lp_blocking_locks(SNUM(conn)) && !blocking_lock && + NT_STATUS_EQUAL((status), NT_STATUS_FILE_LOCK_CONFLICT)) { + defer_lock = true; + timeout = lp_lock_spin_time(); + } + + if (br_lck && defer_lock) { + /* + * A blocking lock was requested. Package up + * this smb into a queued request and push it + * onto the blocking lock queue. + */ + if(push_blocking_lock_request(br_lck, + req, + fsp, + timeout, + i, + e->smbpid, + e->brltype, + WINDOWS_LOCK, + e->offset, + e->count, + block_smbpid)) { + TALLOC_FREE(br_lck); + *async = true; + return NT_STATUS_OK; + } + } + + TALLOC_FREE(br_lck); + } + + if (!NT_STATUS_IS_OK(status)) { + break; + } + } + + /* If any of the above locks failed, then we must unlock + all of the previous locks (X/Open spec). */ + + if (num_locks != 0 && !NT_STATUS_IS_OK(status)) { + + if (type & LOCKING_ANDX_CANCEL_LOCK) { + i = -1; /* we want to skip the for loop */ + } + + /* + * Ensure we don't do a remove on the lock that just failed, + * as under POSIX rules, if we have a lock already there, we + * will delete it (and we shouldn't) ..... + */ + for(i--; i >= 0; i--) { + struct smbd_lock_element *e = &locks[i]; + + do_unlock(smbd_messaging_context(), + fsp, + e->smbpid, + e->count, + e->offset, + WINDOWS_LOCK); + } + return status; + } + + DEBUG(3, ("smbd_do_locking: fnum=%d type=%d num_locks=%d num_ulocks=%d\n", + fsp->fnum, (unsigned int)type, num_locks, num_ulocks)); + + return NT_STATUS_OK; +} + /**************************************************************************** Reply to a lockingX request. ****************************************************************************/ @@ -7235,14 +7410,15 @@ void reply_lockingX(struct smb_request *req) unsigned char oplocklevel; uint16 num_ulocks; uint16 num_locks; - uint64_t count = 0, offset = 0; - uint32 lock_pid; int32 lock_timeout; int i; const uint8_t *data; bool large_file_format; bool err; NTSTATUS status = NT_STATUS_UNSUCCESSFUL; + struct smbd_lock_element *ulocks; + struct smbd_lock_element *locks; + bool async = false; START_PROFILE(SMBlockingX); @@ -7304,7 +7480,8 @@ void reply_lockingX(struct smb_request *req) DEBUG(5,("reply_lockingX: Error : oplock break from " "client for fnum = %d (oplock=%d) and no " "oplock granted on this file (%s).\n", - fsp->fnum, fsp->oplock_type, fsp->fsp_name)); + fsp->fnum, fsp->oplock_type, + fsp_str_dbg(fsp))); /* if this is a pure oplock break request then don't * send a reply */ @@ -7327,7 +7504,7 @@ void reply_lockingX(struct smb_request *req) if (!result) { DEBUG(0, ("reply_lockingX: error in removing " - "oplock on file %s\n", fsp->fsp_name)); + "oplock on file %s\n", fsp_str_dbg(fsp))); /* Hmmm. Is this panic justified? */ smb_panic("internal tdb error"); } @@ -7355,12 +7532,27 @@ void reply_lockingX(struct smb_request *req) return; } + ulocks = talloc_array(req, struct smbd_lock_element, num_ulocks); + if (ulocks == NULL) { + reply_nterror(req, NT_STATUS_NO_MEMORY); + END_PROFILE(SMBlockingX); + return; + } + + locks = talloc_array(req, struct smbd_lock_element, num_locks); + if (locks == NULL) { + reply_nterror(req, NT_STATUS_NO_MEMORY); + END_PROFILE(SMBlockingX); + return; + } + /* Data now points at the beginning of the list of smb_unlkrng structs */ for(i = 0; i < (int)num_ulocks; i++) { - lock_pid = get_lock_pid( data, i, large_file_format); - count = get_lock_count( data, i, large_file_format); - offset = get_lock_offset( data, i, large_file_format, &err); + ulocks[i].smbpid = get_lock_pid(data, i, large_file_format); + ulocks[i].count = get_lock_count(data, i, large_file_format); + ulocks[i].offset = get_lock_offset(data, i, large_file_format, &err); + ulocks[i].brltype = UNLOCK_LOCK; /* * There is no error code marked "stupid client bug".... :-). @@ -7370,32 +7562,6 @@ void reply_lockingX(struct smb_request *req) reply_doserror(req, ERRDOS, ERRnoaccess); return; } - - DEBUG(10,("reply_lockingX: unlock start=%.0f, len=%.0f for " - "pid %u, file %s\n", (double)offset, (double)count, - (unsigned int)lock_pid, fsp->fsp_name )); - - status = do_unlock(smbd_messaging_context(), - fsp, - lock_pid, - count, - offset, - WINDOWS_LOCK); - - DEBUG(10, ("reply_lockingX: unlock returned %s\n", - nt_errstr(status))); - - if (NT_STATUS_V(status)) { - END_PROFILE(SMBlockingX); - reply_nterror(req, status); - return; - } - } - - /* Setup the timeout in seconds. */ - - if (!lp_blocking_locks(SNUM(conn))) { - lock_timeout = 0; } /* Now do any requested locks */ @@ -7405,11 +7571,23 @@ void reply_lockingX(struct smb_request *req) of smb_lkrng structs */ for(i = 0; i < (int)num_locks; i++) { - enum brl_type lock_type = ((locktype & LOCKING_ANDX_SHARED_LOCK) ? - READ_LOCK:WRITE_LOCK); - lock_pid = get_lock_pid( data, i, large_file_format); - count = get_lock_count( data, i, large_file_format); - offset = get_lock_offset( data, i, large_file_format, &err); + locks[i].smbpid = get_lock_pid(data, i, large_file_format); + locks[i].count = get_lock_count(data, i, large_file_format); + locks[i].offset = get_lock_offset(data, i, large_file_format, &err); + + if (locktype & LOCKING_ANDX_SHARED_LOCK) { + if (locktype & LOCKING_ANDX_CANCEL_LOCK) { + locks[i].brltype = PENDING_READ_LOCK; + } else { + locks[i].brltype = READ_LOCK; + } + } else { + if (locktype & LOCKING_ANDX_CANCEL_LOCK) { + locks[i].brltype = PENDING_WRITE_LOCK; + } else { + locks[i].brltype = WRITE_LOCK; + } + } /* * There is no error code marked "stupid client bug".... :-). @@ -7419,154 +7597,22 @@ void reply_lockingX(struct smb_request *req) reply_doserror(req, ERRDOS, ERRnoaccess); return; } - - DEBUG(10,("reply_lockingX: lock start=%.0f, len=%.0f for pid " - "%u, file %s timeout = %d\n", (double)offset, - (double)count, (unsigned int)lock_pid, - fsp->fsp_name, (int)lock_timeout )); - - if (locktype & LOCKING_ANDX_CANCEL_LOCK) { - struct blocking_lock_record *blr = NULL; - - if (lp_blocking_locks(SNUM(conn))) { - - /* Schedule a message to ourselves to - remove the blocking lock record and - return the right error. */ - - blr = blocking_lock_cancel(fsp, - lock_pid, - offset, - count, - WINDOWS_LOCK, - locktype, - NT_STATUS_FILE_LOCK_CONFLICT); - if (blr == NULL) { - END_PROFILE(SMBlockingX); - reply_nterror( - req, - NT_STATUS_DOS( - ERRDOS, - ERRcancelviolation)); - return; - } - } - /* Remove a matching pending lock. */ - status = do_lock_cancel(fsp, - lock_pid, - count, - offset, - WINDOWS_LOCK, - blr); - } else { - bool blocking_lock = lock_timeout ? True : False; - bool defer_lock = False; - struct byte_range_lock *br_lck; - uint32 block_smbpid; - - br_lck = do_lock(smbd_messaging_context(), - fsp, - lock_pid, - count, - offset, - lock_type, - WINDOWS_LOCK, - blocking_lock, - &status, - &block_smbpid, - NULL); - - if (br_lck && blocking_lock && ERROR_WAS_LOCK_DENIED(status)) { - /* Windows internal resolution for blocking locks seems - to be about 200ms... Don't wait for less than that. JRA. */ - if (lock_timeout != -1 && lock_timeout < lp_lock_spin_time()) { - lock_timeout = lp_lock_spin_time(); - } - defer_lock = True; - } - - /* This heuristic seems to match W2K3 very well. If a - lock sent with timeout of zero would fail with NT_STATUS_FILE_LOCK_CONFLICT - it pretends we asked for a timeout of between 150 - 300 milliseconds as - far as I can tell. Replacement for do_lock_spin(). JRA. */ - - if (br_lck && lp_blocking_locks(SNUM(conn)) && !blocking_lock && - NT_STATUS_EQUAL((status), NT_STATUS_FILE_LOCK_CONFLICT)) { - defer_lock = True; - lock_timeout = lp_lock_spin_time(); - } - - if (br_lck && defer_lock) { - /* - * A blocking lock was requested. Package up - * this smb into a queued request and push it - * onto the blocking lock queue. - */ - if(push_blocking_lock_request(br_lck, - req, - fsp, - lock_timeout, - i, - lock_pid, - lock_type, - WINDOWS_LOCK, - offset, - count, - block_smbpid)) { - TALLOC_FREE(br_lck); - END_PROFILE(SMBlockingX); - return; - } - } - - TALLOC_FREE(br_lck); - } - - if (NT_STATUS_V(status)) { - break; - } } - /* If any of the above locks failed, then we must unlock - all of the previous locks (X/Open spec). */ - if (num_locks != 0 && !NT_STATUS_IS_OK(status)) { - - if (locktype & LOCKING_ANDX_CANCEL_LOCK) { - i = -1; /* we want to skip the for loop */ - } - - /* - * Ensure we don't do a remove on the lock that just failed, - * as under POSIX rules, if we have a lock already there, we - * will delete it (and we shouldn't) ..... - */ - for(i--; i >= 0; i--) { - lock_pid = get_lock_pid( data, i, large_file_format); - count = get_lock_count( data, i, large_file_format); - offset = get_lock_offset( data, i, large_file_format, - &err); - - /* - * There is no error code marked "stupid client - * bug".... :-). - */ - if(err) { - END_PROFILE(SMBlockingX); - reply_doserror(req, ERRDOS, ERRnoaccess); - return; - } - - do_unlock(smbd_messaging_context(), - fsp, - lock_pid, - count, - offset, - WINDOWS_LOCK); - } + status = smbd_do_locking(req, fsp, + locktype, lock_timeout, + num_ulocks, ulocks, + num_locks, locks, + &async); + if (!NT_STATUS_IS_OK(status)) { END_PROFILE(SMBlockingX); reply_nterror(req, status); return; } + if (async) { + END_PROFILE(SMBlockingX); + return; + } reply_outbuf(req, 2, 0); @@ -7615,7 +7661,6 @@ void reply_readbs(struct smb_request *req) void reply_setattrE(struct smb_request *req) { connection_struct *conn = req->conn; - struct smb_filename *smb_fname = NULL; struct smb_file_time ft; files_struct *fsp; NTSTATUS status; @@ -7635,14 +7680,6 @@ void reply_setattrE(struct smb_request *req) goto out; } - /* XXX: Remove when fsp->fsp_name is converted to smb_filename. */ - status = create_synthetic_smb_fname_split(talloc_tos(), fsp->fsp_name, - NULL, &smb_fname); - if (!NT_STATUS_IS_OK(status)) { - reply_nterror(req, status); - goto out; - } - /* * Convert the DOS times into unix times. */ @@ -7663,7 +7700,7 @@ void reply_setattrE(struct smb_request *req) /* Ensure we have a valid stat struct for the source. */ if (fsp->fh->fd != -1) { - if (SMB_VFS_FSTAT(fsp, &smb_fname->st) == -1) { + if (SMB_VFS_FSTAT(fsp, &fsp->fsp_name->st) == -1) { status = map_nt_error_from_unix(errno); reply_nterror(req, status); goto out; @@ -7672,9 +7709,9 @@ void reply_setattrE(struct smb_request *req) int ret = -1; if (fsp->posix_open) { - ret = SMB_VFS_LSTAT(conn, smb_fname); + ret = SMB_VFS_LSTAT(conn, fsp->fsp_name); } else { - ret = SMB_VFS_STAT(conn, smb_fname); + ret = SMB_VFS_STAT(conn, fsp->fsp_name); } if (ret == -1) { status = map_nt_error_from_unix(errno); @@ -7683,7 +7720,7 @@ void reply_setattrE(struct smb_request *req) } } - status = smb_set_file_time(conn, fsp, smb_fname, &ft, true); + status = smb_set_file_time(conn, fsp, fsp->fsp_name, &ft, true); if (!NT_STATUS_IS_OK(status)) { reply_doserror(req, ERRDOS, ERRnoaccess); goto out; @@ -7743,8 +7780,6 @@ void reply_getattrE(struct smb_request *req) int mode; files_struct *fsp; struct timespec create_ts; - struct smb_filename *smb_fname = NULL; - NTSTATUS status; START_PROFILE(SMBgetattrE); @@ -7764,21 +7799,14 @@ void reply_getattrE(struct smb_request *req) /* Do an fstat on this file */ if(fsp_stat(fsp, &sbuf)) { - reply_unixerror(req, ERRDOS, ERRnoaccess); + reply_nterror(req, map_nt_error_from_unix(errno)); END_PROFILE(SMBgetattrE); return; } - status = create_synthetic_smb_fname_split(talloc_tos(), fsp->fsp_name, - &sbuf, &smb_fname); - if (!NT_STATUS_IS_OK(status)) { - reply_nterror(req, status); - END_PROFILE(SMBgetattrE); - return; - } + fsp->fsp_name->st = sbuf; - mode = dos_mode(conn, smb_fname); - TALLOC_FREE(smb_fname); + mode = dos_mode(conn, fsp->fsp_name); /* * Convert the times into dos times. Set create diff --git a/source3/smbd/server.c b/source3/smbd/server.c index 6951fac171..4b1c803d75 100644 --- a/source3/smbd/server.c +++ b/source3/smbd/server.c @@ -94,6 +94,7 @@ static void smb_conf_updated(struct messaging_context *msg, { DEBUG(10,("smb_conf_updated: Got message saying smb.conf was " "updated. Reloading.\n")); + change_to_root_user(); reload_services(False); } @@ -868,6 +869,7 @@ static void exit_server_common(enum server_exit_reason how, if (am_parent) { pidfile_unlink(); } + gencache_stabilize(); } /* if we had any open SMB connections when we exited then we diff --git a/source3/smbd/service.c b/source3/smbd/service.c index 0124b2b047..a043288bc9 100644 --- a/source3/smbd/service.c +++ b/source3/smbd/service.c @@ -182,8 +182,8 @@ bool set_current_service(connection_struct *conn, uint16 flags, bool do_chdir) if (do_chdir && vfs_ChDir(conn,conn->connectpath) != 0 && vfs_ChDir(conn,conn->origpath) != 0) { - DEBUG(0,("chdir (%s) failed\n", - conn->connectpath)); + DEBUG(((errno!=EACCES)?0:3),("chdir (%s) failed, reason: %s\n", + conn->connectpath, strerror(errno))); return(False); } diff --git a/source3/smbd/sesssetup.c b/source3/smbd/sesssetup.c index 3988105fa4..2d2e5141ee 100644 --- a/source3/smbd/sesssetup.c +++ b/source3/smbd/sesssetup.c @@ -1807,6 +1807,7 @@ void reply_sesssetup_and_X(struct smb_request *req) SSVAL(req->outbuf,smb_uid,sess_vuid); SSVAL(req->inbuf,smb_uid,sess_vuid); + req->vuid = sess_vuid; if (!sconn->smb1.sessions.done_sesssetup) { sconn->smb1.sessions.max_send = diff --git a/source3/smbd/smb2_close.c b/source3/smbd/smb2_close.c index 6724e5cc15..acb5da7751 100644 --- a/source3/smbd/smb2_close.c +++ b/source3/smbd/smb2_close.c @@ -107,11 +107,6 @@ static NTSTATUS smbd_smb2_close(struct smbd_smb2_request *req, return NT_STATUS_NO_MEMORY; } - /* If it's an IPC, pass off the pipe handler. */ - if (IS_IPC(conn)) { - return NT_STATUS_NOT_IMPLEMENTED; - } - fsp = file_fsp(smbreq, (uint16_t)in_file_id_volatile); if (fsp == NULL) { return NT_STATUS_FILE_CLOSED; @@ -126,7 +121,7 @@ static NTSTATUS smbd_smb2_close(struct smbd_smb2_request *req, status = close_file(smbreq, fsp, NORMAL_CLOSE); if (!NT_STATUS_IS_OK(status)) { DEBUG(5,("smbd_smb2_close: close_file[%s]: %s\n", - fsp->fsp_name, nt_errstr(status))); + fsp_str_dbg(fsp), nt_errstr(status))); return status; } diff --git a/source3/smbd/smb2_create.c b/source3/smbd/smb2_create.c index bdff1939e5..b455f82d80 100644 --- a/source3/smbd/smb2_create.c +++ b/source3/smbd/smb2_create.c @@ -259,7 +259,6 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx, files_struct *result; int info; SMB_STRUCT_STAT sbuf; - struct smb_filename *smb_fname = NULL; req = tevent_req_create(mem_ctx, &state, struct smbd_smb2_create_state); @@ -316,6 +315,8 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx, } info = FILE_WAS_CREATED; } else { + struct smb_filename *smb_fname = NULL; + /* these are ignored for SMB2 */ in_create_options &= ~(0x10);/* NTCREATEX_OPTIONS_SYNC_ALERT */ in_create_options &= ~(0x20);/* NTCREATEX_OPTIONS_ASYNC_ALERT */ @@ -324,10 +325,10 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx, smbreq->conn, smbreq->flags2 & FLAGS2_DFS_PATHNAMES, in_name, - &smb_fname, - NULL); + &smb_fname); if (!NT_STATUS_IS_OK(status)) { tevent_req_nterror(req, status); + TALLOC_FREE(smb_fname); goto out; } @@ -348,19 +349,11 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx, &info); if (!NT_STATUS_IS_OK(status)) { tevent_req_nterror(req, status); + TALLOC_FREE(smb_fname); goto out; } sbuf = smb_fname->st; - } - - if (!smb_fname) { - status = create_synthetic_smb_fname_split(talloc_tos(), - result->fsp_name, - &sbuf, &smb_fname); - if (!NT_STATUS_IS_OK(status)) { - tevent_req_nterror(req, status); - goto out; - } + TALLOC_FREE(smb_fname); } smb2req->compat_chain_fsp = smbreq->chain_fsp; @@ -379,7 +372,7 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx, state->out_allocation_size = sbuf.st_ex_blksize * sbuf.st_ex_blocks; state->out_end_of_file = sbuf.st_ex_size; state->out_file_attributes = dos_mode(result->conn, - smb_fname); + result->fsp_name); if (state->out_file_attributes == 0) { state->out_file_attributes = FILE_ATTRIBUTE_NORMAL; } @@ -387,7 +380,6 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx, tevent_req_done(req); out: - TALLOC_FREE(smb_fname); return tevent_req_post(req, ev); } diff --git a/source3/smbd/smb2_flush.c b/source3/smbd/smb2_flush.c index 8ce683923b..1d3ae2eb06 100644 --- a/source3/smbd/smb2_flush.c +++ b/source3/smbd/smb2_flush.c @@ -176,7 +176,7 @@ static struct tevent_req *smbd_smb2_flush_send(TALLOC_CTX *mem_ctx, status = sync_file(smbreq->conn, fsp, true); if (!NT_STATUS_IS_OK(status)) { DEBUG(5,("smbd_smb2_flush: sync_file for %s returned %s\n", - fsp->fsp_name, nt_errstr(status))); + fsp_str_dbg(fsp), nt_errstr(status))); tevent_req_nterror(req, status); return tevent_req_post(req, ev); } diff --git a/source3/smbd/smb2_getinfo.c b/source3/smbd/smb2_getinfo.c index ba725fdec9..5a6e3d7ecb 100644 --- a/source3/smbd/smb2_getinfo.c +++ b/source3/smbd/smb2_getinfo.c @@ -233,7 +233,177 @@ static struct tevent_req *smbd_smb2_getinfo_send(TALLOC_CTX *mem_ctx, return tevent_req_post(req, ev); } - tevent_req_nterror(req, NT_STATUS_NOT_IMPLEMENTED); + if (IS_IPC(conn)) { + tevent_req_nterror(req, NT_STATUS_NOT_SUPPORTED); + return tevent_req_post(req, ev); + } + + switch (in_info_type) { + case 0x01:/* SMB2_GETINFO_FILE */ + { + uint16_t file_info_level; + char *data = NULL; + unsigned int data_size = 0; + bool delete_pending = false; + struct timespec write_time_ts; + struct file_id fileid; + struct ea_list *ea_list = NULL; + int lock_data_count = 0; + char *lock_data = NULL; + bool ms_dfs_link = false; + NTSTATUS status; + + ZERO_STRUCT(write_time_ts); + + switch (in_file_info_class) { + case 0x0F:/* RAW_FILEINFO_SMB2_ALL_EAS */ + file_info_level = 0xFF00 | in_file_info_class; + break; + + case 0x12:/* RAW_FILEINFO_SMB2_ALL_INFORMATION */ + file_info_level = 0xFF00 | in_file_info_class; + break; + + default: + /* the levels directly map to the passthru levels */ + file_info_level = in_file_info_class + 1000; + break; + } + + if (fsp->fake_file_handle) { + /* + * This is actually for the QUOTA_FAKE_FILE --metze + */ + + /* We know this name is ok, it's already passed the checks. */ + + } else if (fsp && (fsp->is_directory || fsp->fh->fd == -1)) { + /* + * This is actually a QFILEINFO on a directory + * handle (returned from an NT SMB). NT5.0 seems + * to do this call. JRA. + */ + + if (INFO_LEVEL_IS_UNIX(file_info_level)) { + /* Always do lstat for UNIX calls. */ + if (SMB_VFS_LSTAT(conn, fsp->fsp_name)) { + DEBUG(3,("smbd_smb2_getinfo_send: " + "SMB_VFS_LSTAT of %s failed " + "(%s)\n", fsp_str_dbg(fsp), + strerror(errno))); + status = map_nt_error_from_unix(errno); + tevent_req_nterror(req, status); + return tevent_req_post(req, ev); + } + } else if (SMB_VFS_STAT(conn, fsp->fsp_name)) { + DEBUG(3,("smbd_smb2_getinfo_send: " + "SMB_VFS_STAT of %s failed (%s)\n", + fsp_str_dbg(fsp), + strerror(errno))); + status = map_nt_error_from_unix(errno); + tevent_req_nterror(req, status); + return tevent_req_post(req, ev); + } + + fileid = vfs_file_id_from_sbuf(conn, + &fsp->fsp_name->st); + get_file_infos(fileid, &delete_pending, &write_time_ts); + } else { + /* + * Original code - this is an open file. + */ + + if (SMB_VFS_FSTAT(fsp, &fsp->fsp_name->st) != 0) { + DEBUG(3, ("smbd_smb2_getinfo_send: " + "fstat of fnum %d failed (%s)\n", + fsp->fnum, strerror(errno))); + status = map_nt_error_from_unix(errno); + tevent_req_nterror(req, status); + return tevent_req_post(req, ev); + } + fileid = vfs_file_id_from_sbuf(conn, + &fsp->fsp_name->st); + get_file_infos(fileid, &delete_pending, &write_time_ts); + } + + status = smbd_do_qfilepathinfo(conn, state, + file_info_level, + fsp, + fsp->fsp_name, + delete_pending, + write_time_ts, + ms_dfs_link, + ea_list, + lock_data_count, + lock_data, + STR_UNICODE, + in_output_buffer_length, + &data, + &data_size); + if (!NT_STATUS_IS_OK(status)) { + SAFE_FREE(data); + if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_LEVEL)) { + status = NT_STATUS_INVALID_INFO_CLASS; + } + tevent_req_nterror(req, status); + return tevent_req_post(req, ev); + } + if (data_size > 0) { + state->out_output_buffer = data_blob_talloc(state, + data, + data_size); + SAFE_FREE(data); + if (tevent_req_nomem(state->out_output_buffer.data, req)) { + return tevent_req_post(req, ev); + } + } + SAFE_FREE(data); + break; + } + + case 0x02:/* SMB2_GETINFO_FS */ + { + uint16_t file_info_level; + char *data = NULL; + int data_size = 0; + NTSTATUS status; + + /* the levels directly map to the passthru levels */ + file_info_level = in_file_info_class + 1000; + + status = smbd_do_qfsinfo(conn, state, + file_info_level, + STR_UNICODE, + in_output_buffer_length, + &data, + &data_size); + if (!NT_STATUS_IS_OK(status)) { + SAFE_FREE(data); + if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_LEVEL)) { + status = NT_STATUS_INVALID_INFO_CLASS; + } + tevent_req_nterror(req, status); + return tevent_req_post(req, ev); + } + if (data_size > 0) { + state->out_output_buffer = data_blob_talloc(state, + data, + data_size); + SAFE_FREE(data); + if (tevent_req_nomem(state->out_output_buffer.data, req)) { + return tevent_req_post(req, ev); + } + } + SAFE_FREE(data); + break; + } + + default: + tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); + return tevent_req_post(req, ev); + } + + tevent_req_done(req); return tevent_req_post(req, ev); } diff --git a/source3/smbd/smb2_lock.c b/source3/smbd/smb2_lock.c index 3ffe053481..121b4eb24d 100644 --- a/source3/smbd/smb2_lock.c +++ b/source3/smbd/smb2_lock.c @@ -31,6 +31,7 @@ struct smbd_smb2_lock_element { static struct tevent_req *smbd_smb2_lock_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct smbd_smb2_request *smb2req, + uint32_t in_smbpid, uint64_t in_file_id_volatile, uint16_t in_lock_count, struct smbd_smb2_lock_element *in_locks); @@ -41,15 +42,17 @@ NTSTATUS smbd_smb2_request_process_lock(struct smbd_smb2_request *req) { const uint8_t *inhdr; const uint8_t *inbody; - int i = req->current_idx; + const int i = req->current_idx; size_t expected_body_size = 0x30; size_t body_size; + uint32_t in_smbpid; uint16_t in_lock_count; uint64_t in_file_id_persistent; uint64_t in_file_id_volatile; struct smbd_smb2_lock_element *in_locks; struct tevent_req *subreq; const uint8_t *lock_buffer; + uint16_t l; inhdr = (const uint8_t *)req->in.vector[i+0].iov_base; if (req->in.vector[i+1].iov_len != (expected_body_size & 0xFFFFFFFE)) { @@ -63,8 +66,10 @@ NTSTATUS smbd_smb2_request_process_lock(struct smbd_smb2_request *req) return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); } + in_smbpid = IVAL(inhdr, SMB2_HDR_PID); + in_lock_count = CVAL(inbody, 0x02); - /* 0x04 4 bytes reserved */ + /* 0x04 - 4 bytes reserved */ in_file_id_persistent = BVAL(inbody, 0x08); in_file_id_volatile = BVAL(inbody, 0x10); @@ -88,19 +93,21 @@ NTSTATUS smbd_smb2_request_process_lock(struct smbd_smb2_request *req) return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY); } - i = 0; + l = 0; lock_buffer = inbody + 0x18; - in_locks[i].offset = BVAL(lock_buffer, 0x00); - in_locks[i].length = BVAL(lock_buffer, 0x08); - in_locks[i].flags = BVAL(lock_buffer, 0x10); + in_locks[l].offset = BVAL(lock_buffer, 0x00); + in_locks[l].length = BVAL(lock_buffer, 0x08); + in_locks[l].flags = IVAL(lock_buffer, 0x10); + /* 0x14 - 4 reserved bytes */ lock_buffer = (const uint8_t *)req->in.vector[i+2].iov_base; - for (i=1; i < in_lock_count; i++) { - in_locks[i].offset = BVAL(lock_buffer, 0x00); - in_locks[i].length = BVAL(lock_buffer, 0x08); - in_locks[i].flags = BVAL(lock_buffer, 0x10); + for (l=1; l < in_lock_count; l++) { + in_locks[l].offset = BVAL(lock_buffer, 0x00); + in_locks[l].length = BVAL(lock_buffer, 0x08); + in_locks[l].flags = IVAL(lock_buffer, 0x10); + /* 0x14 - 4 reserved bytes */ lock_buffer += 0x18; } @@ -108,6 +115,7 @@ NTSTATUS smbd_smb2_request_process_lock(struct smbd_smb2_request *req) subreq = smbd_smb2_lock_send(req, req->conn->smb2.event_ctx, req, + in_smbpid, in_file_id_volatile, in_lock_count, in_locks); @@ -172,6 +180,7 @@ struct smbd_smb2_lock_state { static struct tevent_req *smbd_smb2_lock_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct smbd_smb2_request *smb2req, + uint32_t in_smbpid, uint64_t in_file_id_volatile, uint16_t in_lock_count, struct smbd_smb2_lock_element *in_locks) @@ -181,6 +190,12 @@ static struct tevent_req *smbd_smb2_lock_send(TALLOC_CTX *mem_ctx, struct smb_request *smbreq; connection_struct *conn = smb2req->tcon->compat_conn; files_struct *fsp; + int32_t timeout = -1; + bool isunlock = false; + uint16_t i; + struct smbd_lock_element *locks; + NTSTATUS status; + bool async = false; req = tevent_req_create(mem_ctx, &state, struct smbd_smb2_lock_state); @@ -211,7 +226,150 @@ static struct tevent_req *smbd_smb2_lock_send(TALLOC_CTX *mem_ctx, return tevent_req_post(req, ev); } - tevent_req_nterror(req, NT_STATUS_NOT_IMPLEMENTED); + locks = talloc_array(state, struct smbd_lock_element, in_lock_count); + if (locks == NULL) { + tevent_req_nterror(req, NT_STATUS_NO_MEMORY); + return tevent_req_post(req, ev); + } + + switch (in_locks[0].flags) { + case SMB2_LOCK_FLAG_SHARED: + case SMB2_LOCK_FLAG_EXCLUSIVE: + if (in_lock_count > 1) { + tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); + return tevent_req_post(req, ev); + } + timeout = -1; + break; + + case SMB2_LOCK_FLAG_SHARED|SMB2_LOCK_FLAG_FAIL_IMMEDIATELY: + case SMB2_LOCK_FLAG_EXCLUSIVE|SMB2_LOCK_FLAG_FAIL_IMMEDIATELY: + timeout = 0; + break; + + case SMB2_LOCK_FLAG_UNLOCK: + /* only the first lock gives the UNLOCK bit - see + MS-SMB2 3.3.5.14 */ + isunlock = true; + timeout = 0; + break; + + default: + tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); + return tevent_req_post(req, ev); + } + + for (i=0; i<in_lock_count; i++) { + uint64_t max_count; + bool invalid = false; + + switch (in_locks[i].flags) { + case SMB2_LOCK_FLAG_SHARED: + case SMB2_LOCK_FLAG_EXCLUSIVE: + if (i > 0) { + tevent_req_nterror(req, + NT_STATUS_INVALID_PARAMETER); + return tevent_req_post(req, ev); + } + if (isunlock) { + tevent_req_nterror(req, + NT_STATUS_INVALID_PARAMETER); + return tevent_req_post(req, ev); + } + break; + + case SMB2_LOCK_FLAG_SHARED|SMB2_LOCK_FLAG_FAIL_IMMEDIATELY: + case SMB2_LOCK_FLAG_EXCLUSIVE|SMB2_LOCK_FLAG_FAIL_IMMEDIATELY: + if (isunlock) { + tevent_req_nterror(req, + NT_STATUS_INVALID_PARAMETER); + return tevent_req_post(req, ev); + } + break; + + case SMB2_LOCK_FLAG_UNLOCK: + if (!isunlock) { + tevent_req_nterror(req, + NT_STATUS_INVALID_PARAMETER); + return tevent_req_post(req, ev); + } + break; + + default: + if (isunlock) { + /* + * is the first element was a UNLOCK + * we need to deferr the error response + * to the backend, because we need to process + * all unlock elements before + */ + invalid = true; + break; + } + tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); + return tevent_req_post(req, ev); + } + + locks[i].smbpid = in_smbpid; + locks[i].offset = in_locks[i].offset; + locks[i].count = in_locks[i].length; + + if (in_locks[i].flags & SMB2_LOCK_FLAG_EXCLUSIVE) { + locks[i].brltype = WRITE_LOCK; + } else if (in_locks[i].flags & SMB2_LOCK_FLAG_SHARED) { + locks[i].brltype = READ_LOCK; + } else if (invalid) { + /* + * this is an invalid UNLOCK element + * and the backend needs to test for + * brltype != UNLOCK_LOCK and return + * NT_STATUS_INVALID_PARAMER + */ + locks[i].brltype = READ_LOCK; + } else { + locks[i].brltype = UNLOCK_LOCK; + } + + max_count = UINT64_MAX - locks[i].offset; + if (locks[i].count > max_count) { + tevent_req_nterror(req, NT_STATUS_INVALID_LOCK_RANGE); + return tevent_req_post(req, ev); + } + } + + if (isunlock) { + status = smbd_do_locking(smbreq, fsp, + 0, + timeout, + in_lock_count, + locks, + 0, + NULL, + &async); + } else { + status = smbd_do_locking(smbreq, fsp, + 0, + timeout, + 0, + NULL, + in_lock_count, + locks, + &async); + } + if (!NT_STATUS_IS_OK(status)) { + if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_LOCK_CONFLICT)) { + status = NT_STATUS_LOCK_NOT_GRANTED; + } + tevent_req_nterror(req, status); + return tevent_req_post(req, ev); + } + + if (async) { + tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR); + return tevent_req_post(req, ev); + } + + tevent_req_done(req); return tevent_req_post(req, ev); } diff --git a/source3/smbd/smb2_notify.c b/source3/smbd/smb2_notify.c index 7ab93ce574..f6d83aeeed 100644 --- a/source3/smbd/smb2_notify.c +++ b/source3/smbd/smb2_notify.c @@ -231,7 +231,7 @@ static struct tevent_req *smbd_smb2_notify_send(TALLOC_CTX *mem_ctx, DEBUG(3,("smbd_smb2_notify_send: 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); } diff --git a/source3/smbd/smb2_read.c b/source3/smbd/smb2_read.c index c9f281f73e..42993511ec 100644 --- a/source3/smbd/smb2_read.c +++ b/source3/smbd/smb2_read.c @@ -281,13 +281,13 @@ static struct tevent_req *smbd_smb2_read_send(TALLOC_CTX *mem_ctx, if (nread < 0) { DEBUG(5,("smbd_smb2_read: read_file[%s] nread[%lld]\n", - fsp->fsp_name, (long long)nread)); + fsp_str_dbg(fsp), (long long)nread)); tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED); return tevent_req_post(req, ev); } if (nread == 0 && in_length != 0) { DEBUG(5,("smbd_smb2_read: read_file[%s] end of file\n", - fsp->fsp_name)); + fsp_str_dbg(fsp))); tevent_req_nterror(req, NT_STATUS_END_OF_FILE); return tevent_req_post(req, ev); } diff --git a/source3/smbd/smb2_server.c b/source3/smbd/smb2_server.c index 43afb1b901..204e57d860 100644 --- a/source3/smbd/smb2_server.c +++ b/source3/smbd/smb2_server.c @@ -1339,7 +1339,7 @@ static int smbd_smb2_request_next_vector(struct tstream_context *stream, if (invalid) { /* the caller should check this */ - body_size = 0; + body_size = 2; } if ((body_size % 2) != 0) { @@ -1376,7 +1376,7 @@ static int smbd_smb2_request_next_vector(struct tstream_context *stream, */ memcpy(body, hdr + SMB2_HDR_BODY, 2); vector[0].iov_base = body + 2; - vector[0].iov_len = req->in.vector[idx].iov_len - 2; + vector[0].iov_len = body_size - 2; vector[1] = req->in.vector[idx+1]; diff --git a/source3/smbd/smb2_setinfo.c b/source3/smbd/smb2_setinfo.c index 110ce6c64a..08c4a7f5bf 100644 --- a/source3/smbd/smb2_setinfo.c +++ b/source3/smbd/smb2_setinfo.c @@ -200,7 +200,123 @@ static struct tevent_req *smbd_smb2_setinfo_send(TALLOC_CTX *mem_ctx, return tevent_req_post(req, ev); } - tevent_req_nterror(req, NT_STATUS_NOT_IMPLEMENTED); + if (IS_IPC(conn)) { + tevent_req_nterror(req, NT_STATUS_NOT_SUPPORTED); + return tevent_req_post(req, ev); + } + + switch (in_info_type) { + case 0x01:/* SMB2_SETINFO_FILE */ + { + uint16_t file_info_level; + char *data; + int data_size; + int ret_size = 0; + NTSTATUS status; + + + file_info_level = in_file_info_class + 1000; + if (file_info_level == SMB_FILE_RENAME_INFORMATION) { + file_info_level = 0xFF00 + in_file_info_class; + } + + if (fsp->is_directory || fsp->fh->fd == -1) { + /* + * This is actually a SETFILEINFO on a directory + * handle (returned from an NT SMB). NT5.0 seems + * to do this call. JRA. + */ + if (INFO_LEVEL_IS_UNIX(file_info_level)) { + /* Always do lstat for UNIX calls. */ + if (SMB_VFS_LSTAT(conn, fsp->fsp_name)) { + DEBUG(3,("smbd_smb2_setinfo_send: " + "SMB_VFS_LSTAT of %s failed " + "(%s)\n", fsp_str_dbg(fsp), + strerror(errno))); + status = map_nt_error_from_unix(errno); + tevent_req_nterror(req, status); + return tevent_req_post(req, ev); + } + } else { + if (SMB_VFS_STAT(conn, fsp->fsp_name) != 0) { + DEBUG(3,("smbd_smb2_setinfo_send: " + "fileinfo of %s failed (%s)\n", + fsp_str_dbg(fsp), + strerror(errno))); + status = map_nt_error_from_unix(errno); + tevent_req_nterror(req, status); + return tevent_req_post(req, ev); + } + } + } else if (fsp->print_file) { + /* + * Doing a DELETE_ON_CLOSE should cancel a print job. + */ + if ((file_info_level == SMB_SET_FILE_DISPOSITION_INFO) + && in_input_buffer.length >= 1 + && CVAL(in_input_buffer.data,0)) { + fsp->fh->private_options |= FILE_DELETE_ON_CLOSE; + + DEBUG(3,("smbd_smb2_setinfo_send: " + "Cancelling print job (%s)\n", + fsp_str_dbg(fsp))); + + tevent_req_done(req); + return tevent_req_post(req, ev); + } else { + tevent_req_nterror(req, + NT_STATUS_OBJECT_PATH_INVALID); + return tevent_req_post(req, ev); + } + } else { + /* + * Original code - this is an open file. + */ + + if (SMB_VFS_FSTAT(fsp, &fsp->fsp_name->st) != 0) { + DEBUG(3,("smbd_smb2_setinfo_send: fstat " + "of fnum %d failed (%s)\n", fsp->fnum, + strerror(errno))); + status = map_nt_error_from_unix(errno); + tevent_req_nterror(req, status); + return tevent_req_post(req, ev); + } + } + + data = NULL; + data_size = in_input_buffer.length; + if (data_size > 0) { + data = (char *)SMB_MALLOC_ARRAY(char, data_size); + if (tevent_req_nomem(data, req)) { + + } + memcpy(data, in_input_buffer.data, data_size); + } + + status = smbd_do_setfilepathinfo(conn, smbreq, state, + file_info_level, + fsp, + fsp->fsp_name, + &data, + data_size, + &ret_size); + SAFE_FREE(data); + if (!NT_STATUS_IS_OK(status)) { + if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_LEVEL)) { + status = NT_STATUS_INVALID_INFO_CLASS; + } + tevent_req_nterror(req, status); + return tevent_req_post(req, ev); + } + break; + } + + default: + tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); + return tevent_req_post(req, ev); + } + + tevent_req_done(req); return tevent_req_post(req, ev); } diff --git a/source3/smbd/smb2_write.c b/source3/smbd/smb2_write.c index 31460a01a1..f1606be623 100644 --- a/source3/smbd/smb2_write.c +++ b/source3/smbd/smb2_write.c @@ -272,14 +272,14 @@ static struct tevent_req *smbd_smb2_write_send(TALLOC_CTX *mem_ctx, if (((nwritten == 0) && (in_data.length != 0)) || (nwritten < 0)) { DEBUG(5,("smbd_smb2_write: write_file[%s] disk full\n", - fsp->fsp_name)); + fsp_str_dbg(fsp))); SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock); tevent_req_nterror(req, NT_STATUS_DISK_FULL); return tevent_req_post(req, ev); } DEBUG(3,("smbd_smb2_write: fnum=[%d/%s] length=%d offset=%d wrote=%d\n", - fsp->fnum, fsp->fsp_name, (int)in_data.length, + fsp->fnum, fsp_str_dbg(fsp), (int)in_data.length, (int)in_offset, (int)nwritten)); if (in_flags & 0x00000001) { @@ -289,7 +289,7 @@ static struct tevent_req *smbd_smb2_write_send(TALLOC_CTX *mem_ctx, status = sync_file(conn, fsp, write_through); if (!NT_STATUS_IS_OK(status)) { DEBUG(5,("smbd_smb2_write: sync_file for %s returned %s\n", - fsp->fsp_name, nt_errstr(status))); + fsp_str_dbg(fsp), nt_errstr(status))); SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock); tevent_req_nterror(req, status); return tevent_req_post(req, ev); diff --git a/source3/smbd/statcache.c b/source3/smbd/statcache.c index daed9f8225..da52cc05d4 100644 --- a/source3/smbd/statcache.c +++ b/source3/smbd/statcache.c @@ -175,6 +175,8 @@ bool stat_cache_lookup(connection_struct *conn, DATA_BLOB data_val; char *name; TALLOC_CTX *ctx = talloc_tos(); + struct smb_filename *smb_fname = NULL; + NTSTATUS status; *pp_dirpath = NULL; *pp_start = *pp_name; @@ -274,14 +276,25 @@ bool stat_cache_lookup(connection_struct *conn, "-> [%s]\n", chk_name, translated_path )); DO_PROFILE_INC(statcache_hits); - if (vfs_stat_smb_fname(conn, translated_path, pst) != 0) { + status = create_synthetic_smb_fname(talloc_tos(), translated_path, + NULL, NULL, &smb_fname); + if (!NT_STATUS_IS_OK(status)) { + TALLOC_FREE(chk_name); + TALLOC_FREE(translated_path); + return false; + } + + if (SMB_VFS_STAT(conn, smb_fname) != 0) { /* Discard this entry - it doesn't exist in the filesystem. */ memcache_delete(smbd_memcache(), STAT_CACHE, data_blob_const(chk_name, strlen(chk_name))); TALLOC_FREE(chk_name); TALLOC_FREE(translated_path); + TALLOC_FREE(smb_fname); return False; } + *pst = smb_fname->st; + TALLOC_FREE(smb_fname); if (!sizechanged) { memcpy(*pp_name, translated_path, diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c index 4bf27863bd..856fd9432d 100644 --- a/source3/smbd/trans2.c +++ b/source3/smbd/trans2.c @@ -367,6 +367,69 @@ static unsigned int fill_ea_buffer(TALLOC_CTX *mem_ctx, char *pdata, unsigned in return ret_data_size; } +static NTSTATUS fill_ea_chained_buffer(TALLOC_CTX *mem_ctx, + char *pdata, + unsigned int total_data_size, + unsigned int *ret_data_size, + connection_struct *conn, + struct ea_list *ea_list) +{ + uint8_t *p = (uint8_t *)pdata; + uint8_t *last_start = NULL; + + *ret_data_size = 0; + + if (!lp_ea_support(SNUM(conn))) { + return NT_STATUS_NO_EAS_ON_FILE; + } + + for (; ea_list; ea_list = ea_list->next) { + size_t dos_namelen; + fstring dos_ea_name; + size_t this_size; + + if (last_start) { + SIVAL(last_start, 0, PTR_DIFF(p, last_start)); + } + last_start = p; + + push_ascii_fstring(dos_ea_name, ea_list->ea.name); + dos_namelen = strlen(dos_ea_name); + if (dos_namelen > 255 || dos_namelen == 0) { + return NT_STATUS_INTERNAL_ERROR; + } + if (ea_list->ea.value.length > 65535) { + return NT_STATUS_INTERNAL_ERROR; + } + + this_size = 0x08 + dos_namelen + 1 + ea_list->ea.value.length; + + if (ea_list->next) { + size_t pad = 4 - (this_size % 4); + this_size += pad; + } + + if (this_size > total_data_size) { + return NT_STATUS_INFO_LENGTH_MISMATCH; + } + + /* We know we have room. */ + SIVAL(p, 0x00, 0); /* next offset */ + SCVAL(p, 0x04, ea_list->ea.flags); + SCVAL(p, 0x05, dos_namelen); + SSVAL(p, 0x06, ea_list->ea.value.length); + fstrcpy((char *)(p+0x08), dos_ea_name); + memcpy(p + 0x08 + dos_namelen + 1, ea_list->ea.value.data, ea_list->ea.value.length); + + total_data_size -= this_size; + p += this_size; + } + + *ret_data_size = PTR_DIFF(p, pdata); + DEBUG(10,("fill_ea_chained_buffer: data_size = %u\n", *ret_data_size)); + return NT_STATUS_OK; +} + static unsigned int estimate_ea_size(connection_struct *conn, files_struct *fsp, const char *fname) { size_t total_ea_len = 0; @@ -408,17 +471,13 @@ NTSTATUS set_ea(connection_struct *conn, files_struct *fsp, const struct smb_filename *smb_fname, struct ea_list *ea_list) { char *fname = NULL; - NTSTATUS status; if (!lp_ea_support(SNUM(conn))) { return NT_STATUS_EAS_NOT_SUPPORTED; } - status = get_full_smb_filename(talloc_tos(), smb_fname, - &fname); - if (!NT_STATUS_IS_OK(status)) { - return status; - } + /* For now setting EAs on streams isn't supported. */ + fname = smb_fname->base_name; for (;ea_list; ea_list = ea_list->next) { int ret; @@ -439,8 +498,9 @@ NTSTATUS set_ea(connection_struct *conn, files_struct *fsp, if (ea_list->ea.value.length == 0) { /* Remove the attribute. */ if (fsp && (fsp->fh->fd != -1)) { - DEBUG(10,("set_ea: deleting ea name %s on file %s by file descriptor.\n", - unix_ea_name, fsp->fsp_name)); + DEBUG(10,("set_ea: deleting ea name %s on " + "file %s by file descriptor.\n", + unix_ea_name, fsp_str_dbg(fsp))); ret = SMB_VFS_FREMOVEXATTR(fsp, unix_ea_name); } else { DEBUG(10,("set_ea: deleting ea name %s on file %s.\n", @@ -457,8 +517,9 @@ NTSTATUS set_ea(connection_struct *conn, files_struct *fsp, #endif } else { if (fsp && (fsp->fh->fd != -1)) { - DEBUG(10,("set_ea: setting ea name %s on file %s by file descriptor.\n", - unix_ea_name, fsp->fsp_name)); + DEBUG(10,("set_ea: setting ea name %s on file " + "%s by file descriptor.\n", + unix_ea_name, fsp_str_dbg(fsp))); ret = SMB_VFS_FSETXATTR(fsp, unix_ea_name, ea_list->ea.value.data, ea_list->ea.value.length, 0); } else { @@ -963,8 +1024,7 @@ static void call_trans2open(connection_struct *conn, conn, req->flags2 & FLAGS2_DFS_PATHNAMES, fname, - &smb_fname, - NULL); + &smb_fname); if (!NT_STATUS_IS_OK(status)) { if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { reply_botherror(req, @@ -981,12 +1041,10 @@ static void call_trans2open(connection_struct *conn, goto out; } - if (!map_open_params_to_ntcreate(smb_fname->base_name, deny_mode, - open_ofun, - &access_mask, - &share_mode, - &create_disposition, - &create_options)) { + if (!map_open_params_to_ntcreate(smb_fname, deny_mode, open_ofun, + &access_mask, &share_mode, + &create_disposition, + &create_options)) { reply_doserror(req, ERRDOS, ERRbadaccess); goto out; } @@ -1085,7 +1143,8 @@ static void call_trans2open(connection_struct *conn, SIVAL(params,20,inode); SSVAL(params,24,0); /* Padding. */ if (flags & 8) { - uint32 ea_size = estimate_ea_size(conn, fsp, fsp->fsp_name); + uint32 ea_size = estimate_ea_size(conn, fsp, + fsp->fsp_name->base_name); SIVAL(params, 26, ea_size); } else { SIVAL(params, 26, 0); @@ -1976,7 +2035,7 @@ static void call_trans2findfirst(connection_struct *conn, if (total_params < 13) { reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - return; + goto out; } dirtype = SVAL(params,0); @@ -2014,12 +2073,12 @@ close_if_end = %d requires_resume_key = %d level = 0x%x, max_data_bytes = %d\n", ask_sharemode = false; if (!lp_unix_extensions()) { reply_nterror(req, NT_STATUS_INVALID_LEVEL); - return; + goto out; } break; default: reply_nterror(req, NT_STATUS_INVALID_LEVEL); - return; + goto out; } srvstr_get_path_wcard(ctx, params, req->flags2, &directory, @@ -2027,7 +2086,7 @@ close_if_end = %d requires_resume_key = %d level = 0x%x, max_data_bytes = %d\n", STR_TERMINATE, &ntstatus, &mask_contains_wcard); if (!NT_STATUS_IS_OK(ntstatus)) { reply_nterror(req, ntstatus); - return; + goto out; } ntstatus = resolve_dfspath_wcard(ctx, conn, @@ -2039,32 +2098,27 @@ close_if_end = %d requires_resume_key = %d level = 0x%x, max_data_bytes = %d\n", if (NT_STATUS_EQUAL(ntstatus,NT_STATUS_PATH_NOT_COVERED)) { reply_botherror(req, NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath); - return; + goto out; } reply_nterror(req, ntstatus); - return; + goto out; } ntstatus = unix_convert(ctx, conn, directory, &smb_dname, (UCF_SAVE_LCOMP | UCF_ALLOW_WCARD_LCOMP)); if (!NT_STATUS_IS_OK(ntstatus)) { reply_nterror(req, ntstatus); - return; + goto out; } mask = smb_dname->original_lcomp; - ntstatus = get_full_smb_filename(ctx, smb_dname, &directory); - TALLOC_FREE(smb_dname); - if (!NT_STATUS_IS_OK(ntstatus)) { - reply_nterror(req, ntstatus); - return; - } + directory = smb_dname->base_name; ntstatus = check_name(conn, directory); if (!NT_STATUS_IS_OK(ntstatus)) { reply_nterror(req, ntstatus); - return; + goto out; } p = strrchr_m(directory,'/'); @@ -2074,14 +2128,14 @@ close_if_end = %d requires_resume_key = %d level = 0x%x, max_data_bytes = %d\n", mask = talloc_strdup(ctx,"*"); if (!mask) { reply_nterror(req, NT_STATUS_NO_MEMORY); - return; + goto out; } mask_contains_wcard = True; } directory = talloc_strdup(talloc_tos(), "./"); if (!directory) { reply_nterror(req, NT_STATUS_NO_MEMORY); - return; + goto out; } } else { *p = 0; @@ -2094,7 +2148,7 @@ close_if_end = %d requires_resume_key = %d level = 0x%x, max_data_bytes = %d\n", if (total_data < 4) { reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - return; + goto out; } ea_size = IVAL(pdata,0); @@ -2102,19 +2156,19 @@ close_if_end = %d requires_resume_key = %d level = 0x%x, max_data_bytes = %d\n", DEBUG(4,("call_trans2findfirst: Rejecting EA request with incorrect \ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pdata,0) )); reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - return; + goto out; } if (!lp_ea_support(SNUM(conn))) { reply_doserror(req, ERRDOS, ERReasnotsupported); - return; + goto out; } /* Pull out the list of names. */ ea_list = read_ea_name_list(ctx, pdata + 4, ea_size - 4); if (!ea_list) { reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - return; + goto out; } } @@ -2122,7 +2176,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd *ppdata, max_data_bytes + DIR_ENTRY_SAFETY_MARGIN); if(*ppdata == NULL ) { reply_nterror(req, NT_STATUS_NO_MEMORY); - return; + goto out; } pdata = *ppdata; data_end = pdata + max_data_bytes + DIR_ENTRY_SAFETY_MARGIN - 1; @@ -2131,7 +2185,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd *pparams = (char *)SMB_REALLOC(*pparams, 10); if (*pparams == NULL) { reply_nterror(req, NT_STATUS_NO_MEMORY); - return; + goto out; } params = *pparams; @@ -2150,7 +2204,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd if (!NT_STATUS_IS_OK(ntstatus)) { reply_nterror(req, ntstatus); - return; + goto out; } dptr_num = dptr_dnum(conn->dirptr); @@ -2233,11 +2287,11 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd dptr_close(&dptr_num); if (Protocol < PROTOCOL_NT1) { reply_doserror(req, ERRDOS, ERRnofiles); - return; + goto out; } else { reply_botherror(req, NT_STATUS_NO_SUCH_FILE, ERRDOS, ERRbadfile); - return; + goto out; } } @@ -2276,7 +2330,8 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd char mangled_name[13]; name_to_8_3(mask, mangled_name, True, conn->params); } - + out: + TALLOC_FREE(smb_dname); return; } @@ -2624,67 +2679,54 @@ static void samba_extended_info_version(struct smb_extended_info *extended_info) "%s", samba_version_string()); } -/**************************************************************************** - Reply to a TRANS2_QFSINFO (query filesystem info). -****************************************************************************/ - -static void call_trans2qfsinfo(connection_struct *conn, - struct smb_request *req, - char **pparams, int total_params, - char **ppdata, int total_data, - unsigned int max_data_bytes) +NTSTATUS smbd_do_qfsinfo(connection_struct *conn, + TALLOC_CTX *mem_ctx, + uint16_t info_level, + uint16_t flags2, + unsigned int max_data_bytes, + char **ppdata, + int *ret_data_len) { char *pdata, *end_data; - char *params = *pparams; - uint16 info_level; - int data_len, len; - SMB_STRUCT_STAT st; + int data_len = 0, len; const char *vname = volume_label(SNUM(conn)); int snum = SNUM(conn); char *fstype = lp_fstype(SNUM(conn)); uint32 additional_flags = 0; - - if (total_params < 2) { - reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - return; - } - - info_level = SVAL(params,0); + struct smb_filename *smb_fname_dot = NULL; + SMB_STRUCT_STAT st; + NTSTATUS status; if (IS_IPC(conn)) { if (info_level != SMB_QUERY_CIFS_UNIX_INFO) { - DEBUG(0,("call_trans2qfsinfo: not an allowed " + DEBUG(0,("smbd_do_qfsinfo: not an allowed " "info level (0x%x) on IPC$.\n", (unsigned int)info_level)); - reply_nterror(req, NT_STATUS_ACCESS_DENIED); - return; + return NT_STATUS_ACCESS_DENIED; } } - if (ENCRYPTION_REQUIRED(conn) && !req->encrypted) { - if (info_level != SMB_QUERY_CIFS_UNIX_INFO) { - DEBUG(0,("call_trans2qfsinfo: encryption required " - "and info level 0x%x sent.\n", - (unsigned int)info_level)); - exit_server_cleanly("encryption required " - "on connection"); - return; - } - } + DEBUG(3,("smbd_do_qfsinfo: level = %d\n", info_level)); - DEBUG(3,("call_trans2qfsinfo: level = %d\n", info_level)); + status = create_synthetic_smb_fname(talloc_tos(), ".", NULL, NULL, + &smb_fname_dot); + if (!NT_STATUS_IS_OK(status)) { + return status; + } - if(vfs_stat_smb_fname(conn,".",&st)!=0) { - DEBUG(2,("call_trans2qfsinfo: stat of . failed (%s)\n", strerror(errno))); - reply_doserror(req, ERRSRV, ERRinvdevice); - return; + if(SMB_VFS_STAT(conn, smb_fname_dot) != 0) { + DEBUG(2,("stat of . failed (%s)\n", strerror(errno))); + TALLOC_FREE(smb_fname_dot); + return map_nt_error_from_unix(errno); } + st = smb_fname_dot->st; + TALLOC_FREE(smb_fname_dot); + *ppdata = (char *)SMB_REALLOC( *ppdata, max_data_bytes + DIR_ENTRY_SAFETY_MARGIN); - if (*ppdata == NULL ) { - reply_nterror(req, NT_STATUS_NO_MEMORY); - return; + if (*ppdata == NULL) { + return NT_STATUS_NO_MEMORY; } pdata = *ppdata; @@ -2697,8 +2739,7 @@ static void call_trans2qfsinfo(connection_struct *conn, uint64_t dfree,dsize,bsize,block_size,sectors_per_unit,bytes_per_sector; data_len = 18; if (get_dfree_info(conn,".",False,&bsize,&dfree,&dsize) == (uint64_t)-1) { - reply_unixerror(req, ERRHRD, ERRgeneral); - return; + return map_nt_error_from_unix(errno); } block_size = lp_block_size(snum); @@ -2717,7 +2758,7 @@ static void call_trans2qfsinfo(connection_struct *conn, bytes_per_sector = 512; sectors_per_unit = bsize/bytes_per_sector; - DEBUG(5,("call_trans2qfsinfo : SMB_INFO_ALLOCATION id=%x, bsize=%u, cSectorUnit=%u, \ + DEBUG(5,("smbd_do_qfsinfo : SMB_INFO_ALLOCATION id=%x, bsize=%u, cSectorUnit=%u, \ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)st.st_ex_dev, (unsigned int)bsize, (unsigned int)sectors_per_unit, (unsigned int)bytes_per_sector, (unsigned int)dsize, (unsigned int)dfree)); @@ -2743,13 +2784,13 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)st.st_ex_dev, (u * the pushed string. The change here was adding the STR_TERMINATE. JRA. */ len = srvstr_push( - pdata, req->flags2, + pdata, flags2, pdata+l2_vol_szVolLabel, vname, PTR_DIFF(end_data, pdata+l2_vol_szVolLabel), STR_NOALIGN|STR_TERMINATE); SCVAL(pdata,l2_vol_cch,len); data_len = l2_vol_szVolLabel + len; - DEBUG(5,("call_trans2qfsinfo : time = %x, namelen = %d, name = %s\n", + DEBUG(5,("smbd_do_qfsinfo : time = %x, namelen = %d, name = %s\n", (unsigned)convert_timespec_to_time_t(st.st_ex_ctime), len, vname)); break; @@ -2776,7 +2817,7 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)st.st_ex_dev, (u SIVAL(pdata,4,255); /* Max filename component length */ /* NOTE! the fstype must *not* be null terminated or win98 won't recognise it and will think we can't do long filenames */ - len = srvstr_push(pdata, req->flags2, pdata+12, fstype, + len = srvstr_push(pdata, flags2, pdata+12, fstype, PTR_DIFF(end_data, pdata+12), STR_UNICODE); SIVAL(pdata,8,len); @@ -2785,7 +2826,7 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)st.st_ex_dev, (u case SMB_QUERY_FS_LABEL_INFO: case SMB_FS_LABEL_INFORMATION: - len = srvstr_push(pdata, req->flags2, pdata+4, vname, + len = srvstr_push(pdata, flags2, pdata+4, vname, PTR_DIFF(end_data, pdata+4), 0); data_len = 4 + len; SIVAL(pdata,0,len); @@ -2802,13 +2843,13 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)st.st_ex_dev, (u (str_checksum(get_local_machine_name())<<16)); /* Max label len is 32 characters. */ - len = srvstr_push(pdata, req->flags2, pdata+18, vname, + len = srvstr_push(pdata, flags2, pdata+18, vname, PTR_DIFF(end_data, pdata+18), STR_UNICODE); SIVAL(pdata,12,len); data_len = 18+len; - DEBUG(5,("call_trans2qfsinfo : SMB_QUERY_FS_VOLUME_INFO namelen = %d, vol=%s serv=%s\n", + DEBUG(5,("smbd_do_qfsinfo : SMB_QUERY_FS_VOLUME_INFO namelen = %d, vol=%s serv=%s\n", (int)strlen(vname),vname, lp_servicename(snum))); break; @@ -2818,8 +2859,7 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)st.st_ex_dev, (u uint64_t dfree,dsize,bsize,block_size,sectors_per_unit,bytes_per_sector; data_len = 24; if (get_dfree_info(conn,".",False,&bsize,&dfree,&dsize) == (uint64_t)-1) { - reply_unixerror(req, ERRHRD, ERRgeneral); - return; + return map_nt_error_from_unix(errno); } block_size = lp_block_size(snum); if (bsize < block_size) { @@ -2836,7 +2876,7 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)st.st_ex_dev, (u } bytes_per_sector = 512; sectors_per_unit = bsize/bytes_per_sector; - DEBUG(5,("call_trans2qfsinfo : SMB_QUERY_FS_SIZE_INFO bsize=%u, cSectorUnit=%u, \ + DEBUG(5,("smbd_do_qfsinfo : SMB_QUERY_FS_SIZE_INFO bsize=%u, cSectorUnit=%u, \ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned int)sectors_per_unit, (unsigned int)bytes_per_sector, (unsigned int)dsize, (unsigned int)dfree)); SBIG_UINT(pdata,0,dsize); @@ -2851,8 +2891,7 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned uint64_t dfree,dsize,bsize,block_size,sectors_per_unit,bytes_per_sector; data_len = 32; if (get_dfree_info(conn,".",False,&bsize,&dfree,&dsize) == (uint64_t)-1) { - reply_unixerror(req, ERRHRD, ERRgeneral); - return; + return map_nt_error_from_unix(errno); } block_size = lp_block_size(snum); if (bsize < block_size) { @@ -2869,7 +2908,7 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned } bytes_per_sector = 512; sectors_per_unit = bsize/bytes_per_sector; - DEBUG(5,("call_trans2qfsinfo : SMB_QUERY_FS_FULL_SIZE_INFO bsize=%u, cSectorUnit=%u, \ + DEBUG(5,("smbd_do_qfsinfo : SMB_QUERY_FS_FULL_SIZE_INFO bsize=%u, cSectorUnit=%u, \ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned int)sectors_per_unit, (unsigned int)bytes_per_sector, (unsigned int)dsize, (unsigned int)dfree)); SBIG_UINT(pdata,0,dsize); /* Total Allocation units. */ @@ -2922,24 +2961,23 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned fsp.fnum = -1; /* access check */ - if (conn->server_info->utok.uid != 0) { + if (conn->server_info->utok.uid != sec_initial_uid()) { DEBUG(0,("set_user_quota: access_denied " "service [%s] user [%s]\n", lp_servicename(SNUM(conn)), conn->server_info->unix_name)); - reply_doserror(req, ERRDOS, ERRnoaccess); - return; + return NT_STATUS_ACCESS_DENIED; } if (vfs_get_ntquota(&fsp, SMB_USER_FS_QUOTA_TYPE, NULL, "as)!=0) { DEBUG(0,("vfs_get_ntquota() failed for service [%s]\n",lp_servicename(SNUM(conn)))); - reply_doserror(req, ERRSRV, ERRerror); - return; + return map_nt_error_from_unix(errno); } data_len = 48; - DEBUG(10,("SMB_FS_QUOTA_INFORMATION: for service [%s]\n",lp_servicename(SNUM(conn)))); + DEBUG(10,("SMB_FS_QUOTA_INFORMATION: for service [%s]\n", + lp_servicename(SNUM(conn)))); /* Unknown1 24 NULL bytes*/ SBIG_UINT(pdata,0,(uint64_t)0); @@ -2990,8 +3028,7 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned int encrypt_caps = 0; if (!lp_unix_extensions()) { - reply_nterror(req, NT_STATUS_INVALID_LEVEL); - return; + return NT_STATUS_INVALID_LEVEL; } switch (conn->encrypt_level) { @@ -3036,8 +3073,7 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned vfs_statvfs_struct svfs; if (!lp_unix_extensions()) { - reply_nterror(req, NT_STATUS_INVALID_LEVEL); - return; + return NT_STATUS_INVALID_LEVEL; } rc = SMB_VFS_STATVFS(conn, ".", &svfs); @@ -3052,16 +3088,14 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned SBIG_UINT(pdata,32,svfs.TotalFileNodes); SBIG_UINT(pdata,40,svfs.FreeFileNodes); SBIG_UINT(pdata,48,svfs.FsIdentifier); - DEBUG(5,("call_trans2qfsinfo : SMB_QUERY_POSIX_FS_INFO succsessful\n")); + DEBUG(5,("smbd_do_qfsinfo : SMB_QUERY_POSIX_FS_INFO succsessful\n")); #ifdef EOPNOTSUPP } else if (rc == EOPNOTSUPP) { - reply_nterror(req, NT_STATUS_INVALID_LEVEL); - return; + return NT_STATUS_INVALID_LEVEL; #endif /* EOPNOTSUPP */ } else { DEBUG(0,("vfs_statvfs() failed for service [%s]\n",lp_servicename(SNUM(conn)))); - reply_doserror(req, ERRSRV, ERRerror); - return; + return NT_STATUS_DOS(ERRSRV, ERRerror); } break; } @@ -3073,13 +3107,11 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned int i; if (!lp_unix_extensions()) { - reply_nterror(req, NT_STATUS_INVALID_LEVEL); - return; + return NT_STATUS_INVALID_LEVEL; } if (max_data_bytes < 40) { - reply_nterror(req, NT_STATUS_BUFFER_TOO_SMALL); - return; + return NT_STATUS_BUFFER_TOO_SMALL; } /* We ARE guest if global_sid_Builtin_Guests is @@ -3193,12 +3225,59 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned } /* drop through */ default: - reply_nterror(req, NT_STATUS_INVALID_LEVEL); + return NT_STATUS_INVALID_LEVEL; + } + + *ret_data_len = data_len; + return NT_STATUS_OK; +} + +/**************************************************************************** + Reply to a TRANS2_QFSINFO (query filesystem info). +****************************************************************************/ + +static void call_trans2qfsinfo(connection_struct *conn, + struct smb_request *req, + char **pparams, int total_params, + char **ppdata, int total_data, + unsigned int max_data_bytes) +{ + char *params = *pparams; + uint16_t info_level; + int data_len = 0; + NTSTATUS status; + + if (total_params < 2) { + reply_nterror(req, NT_STATUS_INVALID_PARAMETER); + return; + } + + info_level = SVAL(params,0); + + if (ENCRYPTION_REQUIRED(conn) && !req->encrypted) { + if (info_level != SMB_QUERY_CIFS_UNIX_INFO) { + DEBUG(0,("call_trans2qfsinfo: encryption required " + "and info level 0x%x sent.\n", + (unsigned int)info_level)); + exit_server_cleanly("encryption required " + "on connection"); return; + } } + DEBUG(3,("call_trans2qfsinfo: level = %d\n", info_level)); + + status = smbd_do_qfsinfo(conn, req, + info_level, + req->flags2, + max_data_bytes, + ppdata, &data_len); + if (!NT_STATUS_IS_OK(status)) { + reply_nterror(req, status); + return; + } - send_trans2_replies(conn, req, params, 0, pdata, data_len, + send_trans2_replies(conn, req, params, 0, *ppdata, data_len, max_data_bytes); DEBUG( 4, ( "%s info_level = %d\n", @@ -3369,12 +3448,12 @@ cap_low = 0x%x, cap_high = 0x%x\n", ZERO_STRUCT(quotas); /* access check */ - if ((conn->server_info->utok.uid != 0) + if ((conn->server_info->utok.uid != sec_initial_uid()) ||!CAN_WRITE(conn)) { DEBUG(0,("set_user_quota: access_denied service [%s] user [%s]\n", lp_servicename(SNUM(conn)), conn->server_info->unix_name)); - reply_doserror(req, ERRSRV, ERRaccess); + reply_nterror(req, NT_STATUS_ACCESS_DENIED); return; } @@ -3443,7 +3522,7 @@ cap_low = 0x%x, cap_high = 0x%x\n", /* now set the quotas */ if (vfs_set_ntquota(fsp, SMB_USER_FS_QUOTA_TYPE, NULL, "as)!=0) { DEBUG(0,("vfs_set_ntquota() failed for service [%s]\n",lp_servicename(SNUM(conn)))); - reply_doserror(req, ERRSRV, ERRerror); + reply_nterror(req, map_nt_error_from_unix(errno)); return; } @@ -3878,296 +3957,55 @@ static void call_trans2qpipeinfo(connection_struct *conn, return; } -/**************************************************************************** - Reply to a TRANS2_QFILEPATHINFO or TRANSACT2_QFILEINFO (query file info by - file name or file id). -****************************************************************************/ - -static void call_trans2qfilepathinfo(connection_struct *conn, - struct smb_request *req, - unsigned int tran_call, - char **pparams, int total_params, - char **ppdata, int total_data, - unsigned int max_data_bytes) +NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn, + TALLOC_CTX *mem_ctx, + uint16_t info_level, + files_struct *fsp, + const struct smb_filename *smb_fname, + bool delete_pending, + struct timespec write_time_ts, + bool ms_dfs_link, + struct ea_list *ea_list, + int lock_data_count, + char *lock_data, + uint16_t flags2, + unsigned int max_data_bytes, + char **ppdata, + unsigned int *pdata_size) { - char *params = *pparams; char *pdata = *ppdata; char *dstart, *dend; - uint16 info_level; - int mode=0; - int nlink; - SMB_OFF_T file_size=0; - uint64_t allocation_size=0; - unsigned int data_size = 0; - unsigned int param_size = 2; + unsigned int data_size; + struct timespec create_time_ts, mtime_ts, atime_ts; + time_t create_time, mtime, atime; SMB_STRUCT_STAT sbuf; - char *dos_fname = NULL; - char *fname = NULL; - struct smb_filename *smb_fname = NULL; - char *fullpathname; - char *base_name; char *p; - SMB_OFF_T pos = 0; - bool delete_pending = False; - int len; - time_t create_time, mtime, atime; - struct timespec create_time_ts, mtime_ts, atime_ts; - struct timespec write_time_ts; - files_struct *fsp = NULL; - struct file_id fileid; - struct ea_list *ea_list = NULL; - char *lock_data = NULL; - bool ms_dfs_link = false; - TALLOC_CTX *ctx = talloc_tos(); - NTSTATUS status = NT_STATUS_OK; - - if (!params) { - reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - return; - } - - ZERO_STRUCT(write_time_ts); - - if (tran_call == TRANSACT2_QFILEINFO) { - if (total_params < 4) { - reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - return; - } - - if (IS_IPC(conn)) { - call_trans2qpipeinfo(conn, req, tran_call, - pparams, total_params, - ppdata, total_data, - max_data_bytes); - return; - } - - fsp = file_fsp(req, SVAL(params,0)); - info_level = SVAL(params,2); - - DEBUG(3,("call_trans2qfilepathinfo: TRANSACT2_QFILEINFO: level = %d\n", info_level)); - - if (INFO_LEVEL_IS_UNIX(info_level) && !lp_unix_extensions()) { - reply_nterror(req, NT_STATUS_INVALID_LEVEL); - return; - } - - /* Initial check for valid fsp ptr. */ - if (!check_fsp_open(conn, req, fsp)) { - return; - } - - fname = talloc_strdup(talloc_tos(),fsp->fsp_name); - if (!fname) { - reply_nterror(req, NT_STATUS_NO_MEMORY); - return; - } - - status = create_synthetic_smb_fname_split(talloc_tos(), fname, - NULL, &smb_fname); - if (!NT_STATUS_IS_OK(status)) { - reply_nterror(req, status); - return; - } - - if(fsp->fake_file_handle) { - /* - * This is actually for the QUOTA_FAKE_FILE --metze - */ - - /* We know this name is ok, it's already passed the checks. */ - - } else if(fsp && (fsp->is_directory || fsp->fh->fd == -1)) { - /* - * This is actually a QFILEINFO on a directory - * handle (returned from an NT SMB). NT5.0 seems - * to do this call. JRA. - */ - - if (INFO_LEVEL_IS_UNIX(info_level)) { - /* Always do lstat for UNIX calls. */ - if (SMB_VFS_LSTAT(conn, smb_fname)) { - DEBUG(3,("call_trans2qfilepathinfo: " - "SMB_VFS_LSTAT of %s failed " - "(%s)\n", - smb_fname_str_dbg(smb_fname), - strerror(errno))); - reply_unixerror(req,ERRDOS,ERRbadpath); - return; - } - } else if (SMB_VFS_STAT(conn, smb_fname)) { - DEBUG(3,("call_trans2qfilepathinfo: " - "SMB_VFS_STAT of %s failed (%s)\n", - smb_fname_str_dbg(smb_fname), - strerror(errno))); - reply_unixerror(req, ERRDOS, ERRbadpath); - return; - } - - fileid = vfs_file_id_from_sbuf(conn, &smb_fname->st); - get_file_infos(fileid, &delete_pending, &write_time_ts); - } else { - /* - * Original code - this is an open file. - */ - if (!check_fsp(conn, req, fsp)) { - return; - } - - if (SMB_VFS_FSTAT(fsp, &smb_fname->st) != 0) { - DEBUG(3, ("fstat of fnum %d failed (%s)\n", - fsp->fnum, strerror(errno))); - reply_unixerror(req, ERRDOS, ERRbadfid); - return; - } - pos = fsp->fh->position_information; - fileid = vfs_file_id_from_sbuf(conn, &smb_fname->st); - get_file_infos(fileid, &delete_pending, &write_time_ts); - } - - } else { - /* qpathinfo */ - if (total_params < 7) { - reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - return; - } - - info_level = SVAL(params,0); - - DEBUG(3,("call_trans2qfilepathinfo: TRANSACT2_QPATHINFO: level = %d\n", info_level)); - - if (INFO_LEVEL_IS_UNIX(info_level) && !lp_unix_extensions()) { - reply_nterror(req, NT_STATUS_INVALID_LEVEL); - return; - } - - srvstr_get_path(ctx, params, req->flags2, &fname, ¶ms[6], - total_params - 6, - STR_TERMINATE, &status); - if (!NT_STATUS_IS_OK(status)) { - reply_nterror(req, status); - return; - } - - status = filename_convert(ctx, - conn, - req->flags2 & FLAGS2_DFS_PATHNAMES, - fname, - &smb_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); - return; - } - reply_nterror(req, status); - return; - } - - /* If this is a stream, check if there is a delete_pending. */ - if ((conn->fs_capabilities & FILE_NAMED_STREAMS) - && is_ntfs_stream_smb_fname(smb_fname)) { - struct smb_filename *smb_fname_base = NULL; - - /* Create an smb_filename with stream_name == NULL. */ - status = - create_synthetic_smb_fname(talloc_tos(), - smb_fname->base_name, - NULL, NULL, - &smb_fname_base); - if (!NT_STATUS_IS_OK(status)) { - reply_nterror(req, status); - return; - } - - if (INFO_LEVEL_IS_UNIX(info_level)) { - /* Always do lstat for UNIX calls. */ - if (SMB_VFS_LSTAT(conn, smb_fname_base) != 0) { - DEBUG(3,("call_trans2qfilepathinfo: " - "SMB_VFS_LSTAT of %s failed " - "(%s)\n", - smb_fname_str_dbg(smb_fname_base), - strerror(errno))); - TALLOC_FREE(smb_fname_base); - reply_unixerror(req,ERRDOS,ERRbadpath); - return; - } - } else { - if (SMB_VFS_STAT(conn, smb_fname_base) != 0) { - DEBUG(3,("call_trans2qfilepathinfo: " - "fileinfo of %s failed " - "(%s)\n", - smb_fname_str_dbg(smb_fname_base), - strerror(errno))); - TALLOC_FREE(smb_fname_base); - reply_unixerror(req,ERRDOS,ERRbadpath); - return; - } - } - - fileid = vfs_file_id_from_sbuf(conn, - &smb_fname_base->st); - TALLOC_FREE(smb_fname_base); - get_file_infos(fileid, &delete_pending, NULL); - if (delete_pending) { - reply_nterror(req, NT_STATUS_DELETE_PENDING); - return; - } - } - - if (INFO_LEVEL_IS_UNIX(info_level)) { - /* Always do lstat for UNIX calls. */ - if (SMB_VFS_LSTAT(conn, smb_fname)) { - DEBUG(3,("call_trans2qfilepathinfo: " - "SMB_VFS_LSTAT of %s failed (%s)\n", - smb_fname_str_dbg(smb_fname), - strerror(errno))); - reply_unixerror(req, ERRDOS, ERRbadpath); - return; - } - - } else if (!VALID_STAT(smb_fname->st) && - SMB_VFS_STAT(conn, smb_fname) && - (info_level != SMB_INFO_IS_NAME_VALID)) { - ms_dfs_link = check_msdfs_link(conn, fname, - &smb_fname->st); - - if (!ms_dfs_link) { - DEBUG(3,("call_trans2qfilepathinfo: " - "SMB_VFS_STAT of %s failed (%s)\n", - smb_fname_str_dbg(smb_fname), - strerror(errno))); - reply_unixerror(req, ERRDOS, ERRbadpath); - return; - } - } - - fileid = vfs_file_id_from_sbuf(conn, &smb_fname->st); - get_file_infos(fileid, &delete_pending, &write_time_ts); - if (delete_pending) { - reply_nterror(req, NT_STATUS_DELETE_PENDING); - return; - } - } + char *fname; + char *base_name; + char *dos_fname; + int mode; + int nlink; + NTSTATUS status; + uint64_t file_size = 0; + uint64_t pos = 0; + uint64_t allocation_size = 0; + uint64_t file_index = 0; + uint32_t access_mask = 0; - /* Set sbuf for use below. */ sbuf = smb_fname->st; if (INFO_LEVEL_IS_UNIX(info_level) && !lp_unix_extensions()) { - reply_nterror(req, NT_STATUS_INVALID_LEVEL); - return; + return NT_STATUS_INVALID_LEVEL; } - DEBUG(3,("call_trans2qfilepathinfo %s (fnum = %d) level=%d call=%d total_data=%d\n", - fname,fsp ? fsp->fnum : -1, info_level,tran_call,total_data)); + status = get_full_smb_filename(mem_ctx, smb_fname, &fname); + if (!NT_STATUS_IS_OK(status)) { + return status; + } - p = strrchr_m(smb_fname->base_name,'/'); - if (!p) - base_name = smb_fname->base_name; - else - base_name = p+1; + DEBUG(5,("smbd_do_qfilepathinfo: %s (fnum = %d) level=%d max_data=%u\n", + smb_fname_str_dbg(smb_fname), fsp ? fsp->fnum : -1, + info_level, max_data_bytes)); if (ms_dfs_link) { mode = dos_mode_msdfs(conn, smb_fname); @@ -4187,102 +4025,15 @@ static void call_trans2qfilepathinfo(connection_struct *conn, nlink -= 1; } - fullpathname = fname; - if (!(mode & aDIR)) - file_size = get_file_size_stat(&sbuf); - - /* Pull out any data sent here before we realloc. */ - switch (info_level) { - case SMB_INFO_QUERY_EAS_FROM_LIST: - { - /* Pull any EA list from the data portion. */ - uint32 ea_size; - - if (total_data < 4) { - reply_nterror( - req, NT_STATUS_INVALID_PARAMETER); - return; - } - ea_size = IVAL(pdata,0); - - if (total_data > 0 && ea_size != total_data) { - DEBUG(4,("call_trans2qfilepathinfo: Rejecting EA request with incorrect \ -total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pdata,0) )); - reply_nterror( - req, NT_STATUS_INVALID_PARAMETER); - return; - } - - if (!lp_ea_support(SNUM(conn))) { - reply_doserror(req, ERRDOS, - ERReasnotsupported); - return; - } - - /* Pull out the list of names. */ - ea_list = read_ea_name_list(ctx, pdata + 4, ea_size - 4); - if (!ea_list) { - reply_nterror( - req, NT_STATUS_INVALID_PARAMETER); - return; - } - break; - } - - case SMB_QUERY_POSIX_LOCK: - { - if (fsp == NULL || fsp->fh->fd == -1) { - reply_nterror(req, NT_STATUS_INVALID_HANDLE); - return; - } - - if (total_data != POSIX_LOCK_DATA_SIZE) { - reply_nterror( - req, NT_STATUS_INVALID_PARAMETER); - return; - } - - /* Copy the lock range data. */ - lock_data = (char *)TALLOC_MEMDUP( - ctx, pdata, total_data); - if (!lock_data) { - reply_nterror(req, NT_STATUS_NO_MEMORY); - return; - } - } - default: - break; - } - - *pparams = (char *)SMB_REALLOC(*pparams,2); - if (*pparams == NULL) { - reply_nterror(req, NT_STATUS_NO_MEMORY); - return; - } - params = *pparams; - SSVAL(params,0,0); data_size = max_data_bytes + DIR_ENTRY_SAFETY_MARGIN; *ppdata = (char *)SMB_REALLOC(*ppdata, data_size); - if (*ppdata == NULL ) { - reply_nterror(req, NT_STATUS_NO_MEMORY); - return; + if (*ppdata == NULL) { + return NT_STATUS_NO_MEMORY; } pdata = *ppdata; dstart = pdata; dend = dstart + data_size - 1; - allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn,fsp,&sbuf); - - if (!fsp) { - /* Do we have this path open ? */ - files_struct *fsp1; - fileid = vfs_file_id_from_sbuf(conn, &sbuf); - fsp1 = file_find_di_first(fileid); - if (fsp1 && fsp1->initial_allocation_size) { - allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn, fsp1, &sbuf); - } - } - if (!null_timespec(write_time_ts) && !INFO_LEVEL_IS_UNIX(info_level)) { update_stat_ex_mtime(&sbuf, write_time_ts); } @@ -4301,28 +4052,67 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd mtime = convert_timespec_to_time_t(mtime_ts); atime = convert_timespec_to_time_t(atime_ts); + p = strrchr_m(smb_fname->base_name,'/'); + if (!p) + base_name = smb_fname->base_name; + else + base_name = p+1; + /* NT expects the name to be in an exact form of the *full* filename. See the trans2 torture test */ if (ISDOT(base_name)) { - dos_fname = talloc_strdup(ctx, "\\"); + dos_fname = talloc_strdup(mem_ctx, "\\"); if (!dos_fname) { - reply_nterror(req, NT_STATUS_NO_MEMORY); - return; + return NT_STATUS_NO_MEMORY; } } else { - dos_fname = talloc_asprintf(ctx, + dos_fname = talloc_asprintf(mem_ctx, "\\%s", fname); if (!dos_fname) { - reply_nterror(req, NT_STATUS_NO_MEMORY); - return; + return NT_STATUS_NO_MEMORY; } string_replace(dos_fname, '/', '\\'); } + allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn, fsp, &sbuf); + + if (!fsp) { + /* Do we have this path open ? */ + files_struct *fsp1; + struct file_id fileid = vfs_file_id_from_sbuf(conn, &sbuf); + fsp1 = file_find_di_first(fileid); + if (fsp1 && fsp1->initial_allocation_size) { + allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn, fsp1, &sbuf); + } + } + + if (!(mode & aDIR)) { + file_size = get_file_size_stat(&sbuf); + } + + if (fsp) { + pos = fsp->fh->position_information; + } + + if (fsp) { + access_mask = fsp->access_mask; + } else { + /* GENERIC_EXECUTE mapping from Windows */ + access_mask = 0x12019F; + } + + /* This should be an index number - looks like + dev/ino to me :-) + + I think this causes us to fail the IFSKIT + BasicFileInformationTest. -tpot */ + file_index = ((sbuf.st_ex_ino) & UINT32_MAX); /* FileIndexLow */ + file_index |= ((uint64_t)((sbuf.st_ex_dev) & UINT32_MAX)) << 32; /* FileIndexHigh */ + switch (info_level) { case SMB_INFO_STANDARD: - DEBUG(10,("call_trans2qfilepathinfo: SMB_INFO_STANDARD\n")); + DEBUG(10,("smbd_do_qfilepathinfo: SMB_INFO_STANDARD\n")); data_size = 22; srv_put_dos_date2(pdata,l1_fdateCreation,create_time); srv_put_dos_date2(pdata,l1_fdateLastAccess,atime); @@ -4335,7 +4125,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd case SMB_INFO_QUERY_EA_SIZE: { unsigned int ea_size = estimate_ea_size(conn, fsp, fname); - DEBUG(10,("call_trans2qfilepathinfo: SMB_INFO_QUERY_EA_SIZE\n")); + DEBUG(10,("smbd_do_qfilepathinfo: SMB_INFO_QUERY_EA_SIZE\n")); data_size = 26; srv_put_dos_date2(pdata,0,create_time); srv_put_dos_date2(pdata,4,atime); @@ -4348,14 +4138,13 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd } case SMB_INFO_IS_NAME_VALID: - DEBUG(10,("call_trans2qfilepathinfo: SMB_INFO_IS_NAME_VALID\n")); - if (tran_call == TRANSACT2_QFILEINFO) { + DEBUG(10,("smbd_do_qfilepathinfo: SMB_INFO_IS_NAME_VALID\n")); + if (fsp) { /* os/2 needs this ? really ?*/ - reply_doserror(req, ERRDOS, ERRbadfunc); - return; + return NT_STATUS_DOS(ERRDOS, ERRbadfunc); } + /* This is only reached for qpathinfo */ data_size = 0; - param_size = 0; break; case SMB_INFO_QUERY_EAS_FROM_LIST: @@ -4363,9 +4152,9 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd size_t total_ea_len = 0; struct ea_list *ea_file_list = NULL; - DEBUG(10,("call_trans2qfilepathinfo: SMB_INFO_QUERY_EAS_FROM_LIST\n")); + DEBUG(10,("smbd_do_qfilepathinfo: SMB_INFO_QUERY_EAS_FROM_LIST\n")); - ea_file_list = get_ea_list_from_file(ctx, conn, fsp, fname, &total_ea_len); + ea_file_list = get_ea_list_from_file(mem_ctx, conn, fsp, fname, &total_ea_len); ea_list = ea_list_union(ea_list, ea_file_list, &total_ea_len); if (!ea_list || (total_ea_len > data_size)) { @@ -4374,7 +4163,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd break; } - data_size = fill_ea_buffer(ctx, pdata, data_size, conn, ea_list); + data_size = fill_ea_buffer(mem_ctx, pdata, data_size, conn, ea_list); break; } @@ -4383,16 +4172,45 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd /* We have data_size bytes to put EA's into. */ size_t total_ea_len = 0; - DEBUG(10,("call_trans2qfilepathinfo: SMB_INFO_QUERY_ALL_EAS\n")); + DEBUG(10,("smbd_do_qfilepathinfo: SMB_INFO_QUERY_ALL_EAS\n")); - ea_list = get_ea_list_from_file(ctx, conn, fsp, fname, &total_ea_len); + ea_list = get_ea_list_from_file(mem_ctx, conn, fsp, fname, &total_ea_len); if (!ea_list || (total_ea_len > data_size)) { data_size = 4; SIVAL(pdata,0,4); /* EA List Length must be set to 4 if no EA's. */ break; } - data_size = fill_ea_buffer(ctx, pdata, data_size, conn, ea_list); + data_size = fill_ea_buffer(mem_ctx, pdata, data_size, conn, ea_list); + break; + } + + case 0xFF0F:/*SMB2_INFO_QUERY_ALL_EAS*/ + { + /* We have data_size bytes to put EA's into. */ + size_t total_ea_len = 0; + struct ea_list *ea_file_list = NULL; + + DEBUG(10,("smbd_do_qfilepathinfo: SMB2_INFO_QUERY_ALL_EAS\n")); + + /*TODO: add filtering and index handling */ + + ea_file_list = get_ea_list_from_file(mem_ctx, + conn, fsp, + fname, + &total_ea_len); + if (!ea_file_list) { + return NT_STATUS_NO_EAS_ON_FILE; + } + + status = fill_ea_chained_buffer(mem_ctx, + pdata, + data_size, + &data_size, + conn, ea_file_list); + if (!NT_STATUS_IS_OK(status)) { + return status; + } break; } @@ -4400,10 +4218,10 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd case SMB_QUERY_FILE_BASIC_INFO: if (info_level == SMB_QUERY_FILE_BASIC_INFO) { - DEBUG(10,("call_trans2qfilepathinfo: SMB_QUERY_FILE_BASIC_INFO\n")); + DEBUG(10,("smbd_do_qfilepathinfo: SMB_QUERY_FILE_BASIC_INFO\n")); data_size = 36; /* w95 returns 40 bytes not 36 - why ?. */ } else { - DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_BASIC_INFORMATION\n")); + DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_BASIC_INFORMATION\n")); data_size = 40; SIVAL(pdata,36,0); } @@ -4424,7 +4242,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd case SMB_FILE_STANDARD_INFORMATION: case SMB_QUERY_FILE_STANDARD_INFO: - DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_STANDARD_INFORMATION\n")); + DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_STANDARD_INFORMATION\n")); data_size = 24; SOFF_T(pdata,0,allocation_size); SOFF_T(pdata,8,file_size); @@ -4438,7 +4256,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd case SMB_QUERY_FILE_EA_INFO: { unsigned int ea_size = estimate_ea_size(conn, fsp, fname); - DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_EA_INFORMATION\n")); + DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_EA_INFORMATION\n")); data_size = 4; SIVAL(pdata,0,ea_size); break; @@ -4448,15 +4266,14 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd case SMB_QUERY_FILE_ALT_NAME_INFO: case SMB_FILE_ALTERNATE_NAME_INFORMATION: { + int len; char mangled_name[13]; - DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_ALTERNATE_NAME_INFORMATION\n")); + DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_ALTERNATE_NAME_INFORMATION\n")); if (!name_to_8_3(base_name,mangled_name, True,conn->params)) { - reply_nterror( - req, - NT_STATUS_NO_MEMORY); + return NT_STATUS_NO_MEMORY; } - len = srvstr_push(dstart, req->flags2, + len = srvstr_push(dstart, flags2, pdata+4, mangled_name, PTR_DIFF(dend, pdata+4), STR_UNICODE); @@ -4466,28 +4283,31 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd } case SMB_QUERY_FILE_NAME_INFO: + { + int len; /* this must be *exactly* right for ACLs on mapped drives to work */ - len = srvstr_push(dstart, req->flags2, + len = srvstr_push(dstart, flags2, pdata+4, dos_fname, PTR_DIFF(dend, pdata+4), STR_UNICODE); - DEBUG(10,("call_trans2qfilepathinfo: SMB_QUERY_FILE_NAME_INFO\n")); + DEBUG(10,("smbd_do_qfilepathinfo: SMB_QUERY_FILE_NAME_INFO\n")); data_size = 4 + len; SIVAL(pdata,0,len); break; + } case SMB_FILE_ALLOCATION_INFORMATION: case SMB_QUERY_FILE_ALLOCATION_INFO: - DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_ALLOCATION_INFORMATION\n")); + DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_ALLOCATION_INFORMATION\n")); data_size = 8; SOFF_T(pdata,0,allocation_size); break; case SMB_FILE_END_OF_FILE_INFORMATION: case SMB_QUERY_FILE_END_OF_FILEINFO: - DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_END_OF_FILE_INFORMATION\n")); + DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_END_OF_FILE_INFORMATION\n")); data_size = 8; SOFF_T(pdata,0,file_size); break; @@ -4495,8 +4315,9 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd case SMB_QUERY_FILE_ALL_INFO: case SMB_FILE_ALL_INFORMATION: { + int len; unsigned int ea_size = estimate_ea_size(conn, fsp, fname); - DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_ALL_INFORMATION\n")); + DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_ALL_INFORMATION\n")); put_long_date_timespec(pdata,create_time_ts); put_long_date_timespec(pdata+8,atime_ts); put_long_date_timespec(pdata+16,mtime_ts); /* write time */ @@ -4513,7 +4334,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd pdata += 24; SIVAL(pdata,0,ea_size); pdata += 4; /* EA info */ - len = srvstr_push(dstart, req->flags2, + len = srvstr_push(dstart, flags2, pdata+4, dos_fname, PTR_DIFF(dend, pdata+4), STR_UNICODE); @@ -4522,27 +4343,52 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd data_size = PTR_DIFF(pdata,(*ppdata)); break; } - case SMB_FILE_INTERNAL_INFORMATION: - /* This should be an index number - looks like - dev/ino to me :-) - I think this causes us to fail the IFSKIT - BasicFileInformationTest. -tpot */ + case 0xFF12:/*SMB2_FILE_ALL_INFORMATION*/ + { + int len; + unsigned int ea_size = estimate_ea_size(conn, fsp, fname); + DEBUG(10,("smbd_do_qfilepathinfo: SMB2_FILE_ALL_INFORMATION\n")); + put_long_date_timespec(pdata+0x00,create_time_ts); + put_long_date_timespec(pdata+0x08,atime_ts); + put_long_date_timespec(pdata+0x10,mtime_ts); /* write time */ + put_long_date_timespec(pdata+0x18,mtime_ts); /* change time */ + SIVAL(pdata, 0x20, mode); + SIVAL(pdata, 0x24, 0); /* padding. */ + SBVAL(pdata, 0x28, allocation_size); + SBVAL(pdata, 0x30, file_size); + SIVAL(pdata, 0x38, nlink); + SCVAL(pdata, 0x3C, delete_pending); + SCVAL(pdata, 0x3D, (mode&aDIR)?1:0); + SSVAL(pdata, 0x3E, 0); /* padding */ + SBVAL(pdata, 0x40, file_index); + SIVAL(pdata, 0x48, ea_size); + SIVAL(pdata, 0x4C, access_mask); + SBVAL(pdata, 0x50, pos); + SIVAL(pdata, 0x58, mode); /*TODO: mode != mode fix this!!! */ + SIVAL(pdata, 0x5C, 0); /* No alignment needed. */ + + pdata += 0x60; + + len = srvstr_push(dstart, flags2, + pdata+4, dos_fname, + PTR_DIFF(dend, pdata+4), + STR_UNICODE); + SIVAL(pdata,0,len); + pdata += 4 + len; + data_size = PTR_DIFF(pdata,(*ppdata)); + break; + } + case SMB_FILE_INTERNAL_INFORMATION: - DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_INTERNAL_INFORMATION\n")); - SIVAL(pdata,0,sbuf.st_ex_ino); /* FileIndexLow */ - SIVAL(pdata,4,sbuf.st_ex_dev); /* FileIndexHigh */ + DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_INTERNAL_INFORMATION\n")); + SBVAL(pdata, 0, file_index); data_size = 8; break; case SMB_FILE_ACCESS_INFORMATION: - DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_ACCESS_INFORMATION\n")); - if (fsp) { - SIVAL(pdata,0,fsp->access_mask); - } else { - /* GENERIC_EXECUTE mapping from Windows */ - SIVAL(pdata,0,0x12019F); - } + DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_ACCESS_INFORMATION\n")); + SIVAL(pdata, 0, access_mask); data_size = 4; break; @@ -4551,32 +4397,32 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd { size_t byte_len; byte_len = dos_PutUniCode(pdata+4,dos_fname,(size_t)max_data_bytes,False); - DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_NAME_INFORMATION\n")); + DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_NAME_INFORMATION\n")); SIVAL(pdata,0,byte_len); data_size = 4 + byte_len; break; } case SMB_FILE_DISPOSITION_INFORMATION: - DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_DISPOSITION_INFORMATION\n")); + DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_DISPOSITION_INFORMATION\n")); data_size = 1; SCVAL(pdata,0,delete_pending); break; case SMB_FILE_POSITION_INFORMATION: - DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_POSITION_INFORMATION\n")); + DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_POSITION_INFORMATION\n")); data_size = 8; SOFF_T(pdata,0,pos); break; case SMB_FILE_MODE_INFORMATION: - DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_MODE_INFORMATION\n")); + DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_MODE_INFORMATION\n")); SIVAL(pdata,0,mode); data_size = 4; break; case SMB_FILE_ALIGNMENT_INFORMATION: - DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_ALIGNMENT_INFORMATION\n")); + DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_ALIGNMENT_INFORMATION\n")); SIVAL(pdata,0,0); /* No alignment needed. */ data_size = 4; break; @@ -4594,7 +4440,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd unsigned int num_streams; struct stream_struct *streams; - DEBUG(10,("call_trans2qfilepathinfo: " + DEBUG(10,("smbd_do_qfilepathinfo: " "SMB_FILE_STREAM_INFORMATION\n")); status = SMB_VFS_STREAMINFO( @@ -4604,8 +4450,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd if (!NT_STATUS_IS_OK(status)) { DEBUG(10, ("could not get stream info: %s\n", nt_errstr(status))); - reply_nterror(req, status); - return; + return status; } status = marshall_stream_info(num_streams, streams, @@ -4615,8 +4460,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd if (!NT_STATUS_IS_OK(status)) { DEBUG(10, ("marshall_stream_info failed: %s\n", nt_errstr(status))); - reply_nterror(req, status); - return; + return status; } TALLOC_FREE(streams); @@ -4625,7 +4469,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd } case SMB_QUERY_COMPRESSION_INFO: case SMB_FILE_COMPRESSION_INFORMATION: - DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_COMPRESSION_INFORMATION\n")); + DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_COMPRESSION_INFORMATION\n")); SOFF_T(pdata,0,file_size); SIVAL(pdata,8,0); /* ??? */ SIVAL(pdata,12,0); /* ??? */ @@ -4633,7 +4477,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd break; case SMB_FILE_NETWORK_OPEN_INFORMATION: - DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_NETWORK_OPEN_INFORMATION\n")); + DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_NETWORK_OPEN_INFORMATION\n")); put_long_date_timespec(pdata,create_time_ts); put_long_date_timespec(pdata+8,atime_ts); put_long_date_timespec(pdata+16,mtime_ts); /* write time */ @@ -4646,7 +4490,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd break; case SMB_FILE_ATTRIBUTE_TAG_INFORMATION: - DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_ATTRIBUTE_TAG_INFORMATION\n")); + DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_ATTRIBUTE_TAG_INFORMATION\n")); SIVAL(pdata,0,mode); SIVAL(pdata,4,0); data_size = 8; @@ -4663,7 +4507,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd { int i; - DEBUG(4,("call_trans2qfilepathinfo: SMB_QUERY_FILE_UNIX_BASIC ")); + DEBUG(4,("smbd_do_qfilepathinfo: SMB_QUERY_FILE_UNIX_BASIC ")); for (i=0; i<100; i++) DEBUG(4,("%d=%x, ",i, (*ppdata)[i])); @@ -4679,7 +4523,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd { int i; - DEBUG(4,("call_trans2qfilepathinfo: SMB_QUERY_FILE_UNIX_INFO2 ")); + DEBUG(4,("smbd_do_qfilepathinfo: SMB_QUERY_FILE_UNIX_INFO2 ")); for (i=0; i<100; i++) DEBUG(4,("%d=%x, ",i, (*ppdata)[i])); @@ -4690,33 +4534,28 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd case SMB_QUERY_FILE_UNIX_LINK: { - char *buffer = TALLOC_ARRAY(ctx, char, PATH_MAX+1); + int len; + char *buffer = TALLOC_ARRAY(mem_ctx, char, PATH_MAX+1); if (!buffer) { - reply_nterror(req, NT_STATUS_NO_MEMORY); - return; + return NT_STATUS_NO_MEMORY; } - DEBUG(10,("call_trans2qfilepathinfo: SMB_QUERY_FILE_UNIX_LINK\n")); + DEBUG(10,("smbd_do_qfilepathinfo: SMB_QUERY_FILE_UNIX_LINK\n")); #ifdef S_ISLNK if(!S_ISLNK(sbuf.st_ex_mode)) { - reply_unixerror(req, ERRSRV, - ERRbadlink); - return; + return NT_STATUS_DOS(ERRSRV, ERRbadlink); } #else - reply_unixerror(req, ERRDOS, ERRbadlink); - return; + return NT_STATUS_DOS(ERRDOS, ERRbadlink); #endif - len = SMB_VFS_READLINK(conn,fullpathname, + len = SMB_VFS_READLINK(conn,fname, buffer, PATH_MAX); if (len == -1) { - reply_unixerror(req, ERRDOS, - ERRnoaccess); - return; + return map_nt_error_from_unix(errno); } buffer[len] = 0; - len = srvstr_push(dstart, req->flags2, + len = srvstr_push(dstart, flags2, pdata, buffer, PTR_DIFF(dend, pdata), STR_TERMINATE); @@ -4741,17 +4580,18 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd } if (file_acl == NULL && no_acl_syscall_error(errno)) { - DEBUG(5,("call_trans2qfilepathinfo: ACLs not implemented on filesystem containing %s\n", + DEBUG(5,("smbd_do_qfilepathinfo: ACLs not implemented on filesystem containing %s\n", fname )); - reply_nterror( - req, - NT_STATUS_NOT_IMPLEMENTED); - return; + return NT_STATUS_NOT_IMPLEMENTED; } if (S_ISDIR(sbuf.st_ex_mode)) { if (fsp && fsp->is_directory) { - def_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, fsp->fsp_name, SMB_ACL_TYPE_DEFAULT); + def_acl = + SMB_VFS_SYS_ACL_GET_FILE( + conn, + fsp->fsp_name->base_name, + SMB_ACL_TYPE_DEFAULT); } else { def_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, fname, SMB_ACL_TYPE_DEFAULT); } @@ -4762,7 +4602,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd num_def_acls = count_acl_entries(conn, def_acl); if ( data_size < (num_file_acls + num_def_acls)*SMB_POSIX_ACL_ENTRY_SIZE + SMB_POSIX_ACL_HEADER_SIZE) { - DEBUG(5,("call_trans2qfilepathinfo: data_size too small (%u) need %u\n", + DEBUG(5,("smbd_do_qfilepathinfo: data_size too small (%u) need %u\n", data_size, (unsigned int)((num_file_acls + num_def_acls)*SMB_POSIX_ACL_ENTRY_SIZE + SMB_POSIX_ACL_HEADER_SIZE) )); @@ -4772,10 +4612,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd if (def_acl) { SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl); } - reply_nterror( - req, - NT_STATUS_BUFFER_TOO_SMALL); - return; + return NT_STATUS_BUFFER_TOO_SMALL; } SSVAL(pdata,0,SMB_POSIX_ACL_VERSION); @@ -4788,9 +4625,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd if (def_acl) { SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl); } - reply_nterror( - req, NT_STATUS_INTERNAL_ERROR); - return; + return NT_STATUS_INTERNAL_ERROR; } if (!marshall_posix_acl(conn, pdata + SMB_POSIX_ACL_HEADER_SIZE + (num_file_acls*SMB_POSIX_ACL_ENTRY_SIZE), &sbuf, def_acl)) { if (file_acl) { @@ -4799,10 +4634,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd if (def_acl) { SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl); } - reply_nterror( - req, - NT_STATUS_INTERNAL_ERROR); - return; + return NT_STATUS_INTERNAL_ERROR; } if (file_acl) { @@ -4824,10 +4656,13 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd uint32 lock_pid; enum brl_type lock_type; - if (total_data != POSIX_LOCK_DATA_SIZE) { - reply_nterror( - req, NT_STATUS_INVALID_PARAMETER); - return; + /* We need an open file with a real fd for this. */ + if (!fsp || fsp->is_directory || fsp->fh->fd == -1) { + return NT_STATUS_INVALID_LEVEL; + } + + if (lock_data_count != POSIX_LOCK_DATA_SIZE) { + return NT_STATUS_INVALID_PARAMETER; } switch (SVAL(pdata, POSIX_LOCK_TYPE_OFFSET)) { @@ -4840,10 +4675,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd case POSIX_LOCK_TYPE_UNLOCK: default: /* There's no point in asking for an unlock... */ - reply_nterror( - req, - NT_STATUS_INVALID_PARAMETER); - return; + return NT_STATUS_INVALID_PARAMETER; } lock_pid = IVAL(pdata, POSIX_LOCK_PID_OFFSET); @@ -4888,15 +4720,393 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd memcpy(pdata, lock_data, POSIX_LOCK_DATA_SIZE); SSVAL(pdata, POSIX_LOCK_TYPE_OFFSET, POSIX_LOCK_TYPE_UNLOCK); } else { - reply_nterror(req, status); - return; + return status; } break; } default: + return NT_STATUS_INVALID_LEVEL; + } + + *pdata_size = data_size; + return NT_STATUS_OK; +} + +/**************************************************************************** + Reply to a TRANS2_QFILEPATHINFO or TRANSACT2_QFILEINFO (query file info by + file name or file id). +****************************************************************************/ + +static void call_trans2qfilepathinfo(connection_struct *conn, + struct smb_request *req, + unsigned int tran_call, + char **pparams, int total_params, + char **ppdata, int total_data, + unsigned int max_data_bytes) +{ + char *params = *pparams; + char *pdata = *ppdata; + uint16 info_level; + unsigned int data_size = 0; + unsigned int param_size = 2; + struct smb_filename *smb_fname = NULL; + bool delete_pending = False; + struct timespec write_time_ts; + files_struct *fsp = NULL; + struct file_id fileid; + struct ea_list *ea_list = NULL; + int lock_data_count = 0; + char *lock_data = NULL; + bool ms_dfs_link = false; + NTSTATUS status = NT_STATUS_OK; + + if (!params) { + reply_nterror(req, NT_STATUS_INVALID_PARAMETER); + return; + } + + ZERO_STRUCT(write_time_ts); + + if (tran_call == TRANSACT2_QFILEINFO) { + if (total_params < 4) { + reply_nterror(req, NT_STATUS_INVALID_PARAMETER); + return; + } + + if (IS_IPC(conn)) { + call_trans2qpipeinfo(conn, req, tran_call, + pparams, total_params, + ppdata, total_data, + max_data_bytes); + return; + } + + fsp = file_fsp(req, SVAL(params,0)); + info_level = SVAL(params,2); + + DEBUG(3,("call_trans2qfilepathinfo: TRANSACT2_QFILEINFO: level = %d\n", info_level)); + + if (INFO_LEVEL_IS_UNIX(info_level) && !lp_unix_extensions()) { reply_nterror(req, NT_STATUS_INVALID_LEVEL); return; + } + + /* Initial check for valid fsp ptr. */ + if (!check_fsp_open(conn, req, fsp)) { + return; + } + + status = copy_smb_filename(talloc_tos(), fsp->fsp_name, + &smb_fname); + if (!NT_STATUS_IS_OK(status)) { + reply_nterror(req, status); + return; + } + + if(fsp->fake_file_handle) { + /* + * This is actually for the QUOTA_FAKE_FILE --metze + */ + + /* We know this name is ok, it's already passed the checks. */ + + } else if(fsp->is_directory || fsp->fh->fd == -1) { + /* + * This is actually a QFILEINFO on a directory + * handle (returned from an NT SMB). NT5.0 seems + * to do this call. JRA. + */ + + if (INFO_LEVEL_IS_UNIX(info_level)) { + /* Always do lstat for UNIX calls. */ + if (SMB_VFS_LSTAT(conn, smb_fname)) { + DEBUG(3,("call_trans2qfilepathinfo: " + "SMB_VFS_LSTAT of %s failed " + "(%s)\n", + smb_fname_str_dbg(smb_fname), + strerror(errno))); + reply_nterror(req, + map_nt_error_from_unix(errno)); + return; + } + } else if (SMB_VFS_STAT(conn, smb_fname)) { + DEBUG(3,("call_trans2qfilepathinfo: " + "SMB_VFS_STAT of %s failed (%s)\n", + smb_fname_str_dbg(smb_fname), + strerror(errno))); + reply_nterror(req, + map_nt_error_from_unix(errno)); + return; + } + + fileid = vfs_file_id_from_sbuf(conn, &smb_fname->st); + get_file_infos(fileid, &delete_pending, &write_time_ts); + } else { + /* + * Original code - this is an open file. + */ + if (!check_fsp(conn, req, fsp)) { + return; + } + + if (SMB_VFS_FSTAT(fsp, &smb_fname->st) != 0) { + DEBUG(3, ("fstat of fnum %d failed (%s)\n", + fsp->fnum, strerror(errno))); + reply_nterror(req, + map_nt_error_from_unix(errno)); + return; + } + fileid = vfs_file_id_from_sbuf(conn, &smb_fname->st); + get_file_infos(fileid, &delete_pending, &write_time_ts); + } + + } else { + char *fname = NULL; + + /* qpathinfo */ + if (total_params < 7) { + reply_nterror(req, NT_STATUS_INVALID_PARAMETER); + return; + } + + info_level = SVAL(params,0); + + DEBUG(3,("call_trans2qfilepathinfo: TRANSACT2_QPATHINFO: level = %d\n", info_level)); + + if (INFO_LEVEL_IS_UNIX(info_level) && !lp_unix_extensions()) { + reply_nterror(req, NT_STATUS_INVALID_LEVEL); + return; + } + + srvstr_get_path(req, params, req->flags2, &fname, ¶ms[6], + total_params - 6, + STR_TERMINATE, &status); + if (!NT_STATUS_IS_OK(status)) { + reply_nterror(req, status); + return; + } + + status = filename_convert(req, + conn, + req->flags2 & FLAGS2_DFS_PATHNAMES, + fname, + &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); + return; + } + reply_nterror(req, status); + return; + } + + /* If this is a stream, check if there is a delete_pending. */ + if ((conn->fs_capabilities & FILE_NAMED_STREAMS) + && is_ntfs_stream_smb_fname(smb_fname)) { + struct smb_filename *smb_fname_base = NULL; + + /* Create an smb_filename with stream_name == NULL. */ + status = + create_synthetic_smb_fname(talloc_tos(), + smb_fname->base_name, + NULL, NULL, + &smb_fname_base); + if (!NT_STATUS_IS_OK(status)) { + reply_nterror(req, status); + return; + } + + if (INFO_LEVEL_IS_UNIX(info_level)) { + /* Always do lstat for UNIX calls. */ + if (SMB_VFS_LSTAT(conn, smb_fname_base) != 0) { + DEBUG(3,("call_trans2qfilepathinfo: " + "SMB_VFS_LSTAT of %s failed " + "(%s)\n", + smb_fname_str_dbg(smb_fname_base), + strerror(errno))); + TALLOC_FREE(smb_fname_base); + reply_nterror(req, + map_nt_error_from_unix(errno)); + return; + } + } else { + if (SMB_VFS_STAT(conn, smb_fname_base) != 0) { + DEBUG(3,("call_trans2qfilepathinfo: " + "fileinfo of %s failed " + "(%s)\n", + smb_fname_str_dbg(smb_fname_base), + strerror(errno))); + TALLOC_FREE(smb_fname_base); + reply_nterror(req, + map_nt_error_from_unix(errno)); + return; + } + } + + fileid = vfs_file_id_from_sbuf(conn, + &smb_fname_base->st); + TALLOC_FREE(smb_fname_base); + get_file_infos(fileid, &delete_pending, NULL); + if (delete_pending) { + reply_nterror(req, NT_STATUS_DELETE_PENDING); + return; + } + } + + if (INFO_LEVEL_IS_UNIX(info_level)) { + /* Always do lstat for UNIX calls. */ + if (SMB_VFS_LSTAT(conn, smb_fname)) { + DEBUG(3,("call_trans2qfilepathinfo: " + "SMB_VFS_LSTAT of %s failed (%s)\n", + smb_fname_str_dbg(smb_fname), + strerror(errno))); + reply_nterror(req, + map_nt_error_from_unix(errno)); + return; + } + + } else if (!VALID_STAT(smb_fname->st) && + SMB_VFS_STAT(conn, smb_fname) && + (info_level != SMB_INFO_IS_NAME_VALID)) { + ms_dfs_link = check_msdfs_link(conn, + smb_fname->base_name, + &smb_fname->st); + + if (!ms_dfs_link) { + DEBUG(3,("call_trans2qfilepathinfo: " + "SMB_VFS_STAT of %s failed (%s)\n", + smb_fname_str_dbg(smb_fname), + strerror(errno))); + reply_nterror(req, + map_nt_error_from_unix(errno)); + return; + } + } + + fileid = vfs_file_id_from_sbuf(conn, &smb_fname->st); + get_file_infos(fileid, &delete_pending, &write_time_ts); + if (delete_pending) { + reply_nterror(req, NT_STATUS_DELETE_PENDING); + return; + } + } + + DEBUG(3,("call_trans2qfilepathinfo %s (fnum = %d) level=%d call=%d " + "total_data=%d\n", smb_fname_str_dbg(smb_fname), + fsp ? fsp->fnum : -1, info_level,tran_call,total_data)); + + /* Pull out any data sent here before we realloc. */ + switch (info_level) { + case SMB_INFO_QUERY_EAS_FROM_LIST: + { + /* Pull any EA list from the data portion. */ + uint32 ea_size; + + if (total_data < 4) { + reply_nterror( + req, NT_STATUS_INVALID_PARAMETER); + return; + } + ea_size = IVAL(pdata,0); + + if (total_data > 0 && ea_size != total_data) { + DEBUG(4,("call_trans2qfilepathinfo: Rejecting EA request with incorrect \ +total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pdata,0) )); + reply_nterror( + req, NT_STATUS_INVALID_PARAMETER); + return; + } + + if (!lp_ea_support(SNUM(conn))) { + reply_doserror(req, ERRDOS, + ERReasnotsupported); + return; + } + + /* Pull out the list of names. */ + ea_list = read_ea_name_list(req, pdata + 4, ea_size - 4); + if (!ea_list) { + reply_nterror( + req, NT_STATUS_INVALID_PARAMETER); + return; + } + break; + } + + case SMB_QUERY_POSIX_LOCK: + { + if (fsp == NULL || fsp->fh->fd == -1) { + reply_nterror(req, NT_STATUS_INVALID_HANDLE); + return; + } + + if (total_data != POSIX_LOCK_DATA_SIZE) { + reply_nterror( + req, NT_STATUS_INVALID_PARAMETER); + return; + } + + /* Copy the lock range data. */ + lock_data = (char *)TALLOC_MEMDUP( + req, pdata, total_data); + if (!lock_data) { + reply_nterror(req, NT_STATUS_NO_MEMORY); + return; + } + lock_data_count = total_data; + } + default: + break; + } + + *pparams = (char *)SMB_REALLOC(*pparams,2); + if (*pparams == NULL) { + reply_nterror(req, NT_STATUS_NO_MEMORY); + return; + } + params = *pparams; + SSVAL(params,0,0); + + /* + * draft-leach-cifs-v1-spec-02.txt + * 4.2.14 TRANS2_QUERY_PATH_INFORMATION: Get File Attributes given Path + * says: + * + * The requested information is placed in the Data portion of the + * transaction response. For the information levels greater than 0x100, + * the transaction response has 1 parameter word which should be + * ignored by the client. + * + * However Windows only follows this rule for the IS_NAME_VALID call. + */ + switch (info_level) { + case SMB_INFO_IS_NAME_VALID: + param_size = 0; + break; + } + + if ((info_level & 0xFF00) == 0xFF00) { + /* + * We use levels that start with 0xFF00 + * internally to represent SMB2 specific levels + */ + reply_nterror(req, NT_STATUS_INVALID_LEVEL); + return; + } + + status = smbd_do_qfilepathinfo(conn, req, info_level, + fsp, smb_fname, + delete_pending, write_time_ts, + ms_dfs_link, ea_list, + lock_data_count, lock_data, + req->flags2, max_data_bytes, + ppdata, &data_size); + if (!NT_STATUS_IS_OK(status)) { + reply_nterror(req, status); + return; } send_trans2_replies(conn, req, params, param_size, *ppdata, data_size, @@ -4915,8 +5125,6 @@ NTSTATUS hardlink_internals(TALLOC_CTX *ctx, const struct smb_filename *smb_fname_old, const struct smb_filename *smb_fname_new) { - char *oldname = NULL; - char *newname = NULL; NTSTATUS status = NT_STATUS_OK; /* source must already exist. */ @@ -4934,25 +5142,22 @@ NTSTATUS hardlink_internals(TALLOC_CTX *ctx, return NT_STATUS_FILE_IS_A_DIRECTORY; } - status = get_full_smb_filename(ctx, smb_fname_new, &newname); - if (!NT_STATUS_IS_OK(status)) { - goto out; - } - status = get_full_smb_filename(ctx, smb_fname_old, &oldname); - if (!NT_STATUS_IS_OK(status)) { - goto out; + /* Setting a hardlink to/from a stream isn't currently supported. */ + if (is_ntfs_stream_smb_fname(smb_fname_old) || + is_ntfs_stream_smb_fname(smb_fname_new)) { + return NT_STATUS_INVALID_PARAMETER; } - DEBUG(10,("hardlink_internals: doing hard link %s -> %s\n", newname, oldname )); + DEBUG(10,("hardlink_internals: doing hard link %s -> %s\n", + smb_fname_old->base_name, smb_fname_new->base_name)); - if (SMB_VFS_LINK(conn,oldname,newname) != 0) { + if (SMB_VFS_LINK(conn, smb_fname_old->base_name, + smb_fname_new->base_name) != 0) { status = map_nt_error_from_unix(errno); DEBUG(3,("hardlink_internals: Error %s hard link %s -> %s\n", - nt_errstr(status), newname, oldname)); + nt_errstr(status), smb_fname_old->base_name, + smb_fname_new->base_name)); } - out: - TALLOC_FREE(newname); - TALLOC_FREE(oldname); return status; } @@ -5317,8 +5522,9 @@ static NTSTATUS smb_file_position_information(connection_struct *conn, } #endif /* LARGE_SMB_OFF_T */ - DEBUG(10,("smb_file_position_information: Set file position information for file %s to %.0f\n", - fsp->fsp_name, (double)position_information )); + DEBUG(10,("smb_file_position_information: Set file position " + "information for file %s to %.0f\n", fsp_str_dbg(fsp), + (double)position_information)); fsp->fh->position_information = position_information; return NT_STATUS_OK; } @@ -5351,10 +5557,10 @@ static NTSTATUS smb_set_file_unix_link(connection_struct *conn, struct smb_request *req, const char *pdata, int total_data, - const char *fname) + const struct smb_filename *smb_fname) { char *link_target = NULL; - const char *newname = fname; + const char *newname = smb_fname->base_name; NTSTATUS status = NT_STATUS_OK; TALLOC_CTX *ctx = talloc_tos(); @@ -5454,8 +5660,7 @@ static NTSTATUS smb_set_file_unix_hlink(connection_struct *conn, conn, req->flags2 & FLAGS2_DFS_PATHNAMES, oldname, - &smb_fname_old, - NULL); + &smb_fname_old); if (!NT_STATUS_IS_OK(status)) { return status; } @@ -5529,8 +5734,8 @@ static NTSTATUS smb_file_rename_information(connection_struct *conn, /* Create an smb_fname to call rename_internals_fsp() with. */ status = create_synthetic_smb_fname(talloc_tos(), - fsp->base_fsp->fsp_name, - newname, NULL, &smb_fname); + fsp->base_fsp->fsp_name->base_name, newname, NULL, + &smb_fname); if (!NT_STATUS_IS_OK(status)) { goto out; } @@ -5547,7 +5752,7 @@ static NTSTATUS smb_file_rename_information(connection_struct *conn, /* Create a char * to call rename_internals() with. */ base_name = talloc_asprintf(ctx, "%s%s", - fsp->base_fsp->fsp_name, + fsp->base_fsp->fsp_name->base_name, newname); if (!base_name) { status = NT_STATUS_NO_MEMORY; @@ -5604,13 +5809,15 @@ static NTSTATUS smb_file_rename_information(connection_struct *conn, } if (fsp) { - DEBUG(10,("smb_file_rename_information: SMB_FILE_RENAME_INFORMATION (fnum %d) %s -> %s\n", - fsp->fnum, fsp->fsp_name, base_name )); + DEBUG(10,("smb_file_rename_information: " + "SMB_FILE_RENAME_INFORMATION (fnum %d) %s -> %s\n", + fsp->fnum, fsp_str_dbg(fsp), base_name)); status = rename_internals_fsp(conn, fsp, smb_fname, 0, overwrite); } else { - DEBUG(10,("smb_file_rename_information: SMB_FILE_RENAME_INFORMATION %s -> %s\n", - fname, base_name )); + DEBUG(10,("smb_file_rename_information: " + "SMB_FILE_RENAME_INFORMATION %s -> %s\n", + fname, base_name)); status = rename_internals(ctx, conn, req, fname, base_name, 0, overwrite, False, dest_has_wcard, FILE_WRITE_ATTRIBUTES); @@ -5629,8 +5836,7 @@ static NTSTATUS smb_set_posix_acl(connection_struct *conn, const char *pdata, int total_data, files_struct *fsp, - const char *fname, - SMB_STRUCT_STAT *psbuf) + const struct smb_filename *smb_fname) { uint16 posix_acl_version; uint16 num_file_acls; @@ -5665,18 +5871,20 @@ static NTSTATUS smb_set_posix_acl(connection_struct *conn, } DEBUG(10,("smb_set_posix_acl: file %s num_file_acls = %u, num_def_acls = %u\n", - fname ? fname : fsp->fsp_name, + smb_fname ? smb_fname_str_dbg(smb_fname) : fsp_str_dbg(fsp), (unsigned int)num_file_acls, (unsigned int)num_def_acls)); - if (valid_file_acls && !set_unix_posix_acl(conn, fsp, fname, num_file_acls, - pdata + SMB_POSIX_ACL_HEADER_SIZE)) { + if (valid_file_acls && !set_unix_posix_acl(conn, fsp, + smb_fname->base_name, num_file_acls, + pdata + SMB_POSIX_ACL_HEADER_SIZE)) { return map_nt_error_from_unix(errno); } - if (valid_def_acls && !set_unix_posix_default_acl(conn, fname, psbuf, num_def_acls, - pdata + SMB_POSIX_ACL_HEADER_SIZE + - (num_file_acls*SMB_POSIX_ACL_ENTRY_SIZE))) { + if (valid_def_acls && !set_unix_posix_default_acl(conn, + smb_fname->base_name, &smb_fname->st, num_def_acls, + pdata + SMB_POSIX_ACL_HEADER_SIZE + + (num_file_acls*SMB_POSIX_ACL_ENTRY_SIZE))) { return map_nt_error_from_unix(errno); } return NT_STATUS_OK; @@ -5752,7 +5960,7 @@ static NTSTATUS smb_set_posix_lock(connection_struct *conn, DEBUG(10,("smb_set_posix_lock: file %s, lock_type = %u," "lock_pid = %u, count = %.0f, offset = %.0f\n", - fsp->fsp_name, + fsp_str_dbg(fsp), (unsigned int)lock_type, (unsigned int)lock_pid, (double)count, @@ -6444,11 +6652,9 @@ static NTSTATUS smb_posix_mkdir(connection_struct *conn, struct smb_request *req, char **ppdata, int total_data, - const char *fname, - SMB_STRUCT_STAT *psbuf, + struct smb_filename *smb_fname, int *pdata_return_size) { - struct smb_filename *smb_fname; NTSTATUS status = NT_STATUS_OK; uint32 raw_unixmode = 0; uint32 mod_unixmode = 0; @@ -6465,7 +6671,8 @@ static NTSTATUS smb_posix_mkdir(connection_struct *conn, raw_unixmode = IVAL(pdata,8); /* Next 4 bytes are not yet defined. */ - status = unix_perms_from_wire(conn, psbuf, raw_unixmode, PERM_NEW_DIR, &unixmode); + status = unix_perms_from_wire(conn, &smb_fname->st, raw_unixmode, + PERM_NEW_DIR, &unixmode); if (!NT_STATUS_IS_OK(status)) { return status; } @@ -6473,13 +6680,7 @@ static NTSTATUS smb_posix_mkdir(connection_struct *conn, mod_unixmode = (uint32)unixmode | FILE_FLAG_POSIX_SEMANTICS; DEBUG(10,("smb_posix_mkdir: file %s, mode 0%o\n", - fname, (unsigned int)unixmode )); - - status = create_synthetic_smb_fname_split(talloc_tos(), fname, psbuf, - &smb_fname); - if (!NT_STATUS_IS_OK(status)) { - return status; - } + smb_fname_str_dbg(smb_fname), (unsigned int)unixmode)); status = SMB_VFS_CREATE_FILE( conn, /* conn */ @@ -6498,9 +6699,6 @@ static NTSTATUS smb_posix_mkdir(connection_struct *conn, &fsp, /* result */ &info); /* pinfo */ - *psbuf = smb_fname->st; - TALLOC_FREE(smb_fname); - if (NT_STATUS_IS_OK(status)) { close_file(req, fsp, NORMAL_CLOSE); } @@ -6531,12 +6729,14 @@ static NTSTATUS smb_posix_mkdir(connection_struct *conn, case SMB_QUERY_FILE_UNIX_BASIC: SSVAL(pdata,8,SMB_QUERY_FILE_UNIX_BASIC); SSVAL(pdata,10,0); /* Padding. */ - store_file_unix_basic(conn, pdata + 12, fsp, psbuf); + store_file_unix_basic(conn, pdata + 12, fsp, + &smb_fname->st); break; case SMB_QUERY_FILE_UNIX_INFO2: SSVAL(pdata,8,SMB_QUERY_FILE_UNIX_INFO2); SSVAL(pdata,10,0); /* Padding. */ - store_file_unix_basic_info2(conn, pdata + 12, fsp, psbuf); + store_file_unix_basic_info2(conn, pdata + 12, fsp, + &smb_fname->st); break; default: SSVAL(pdata,8,SMB_NO_INFO_LEVEL_RETURNED); @@ -6555,11 +6755,9 @@ static NTSTATUS smb_posix_open(connection_struct *conn, struct smb_request *req, char **ppdata, int total_data, - const char *fname, - SMB_STRUCT_STAT *psbuf, + struct smb_filename *smb_fname, int *pdata_return_size) { - struct smb_filename *smb_fname = NULL; bool extended_oplock_granted = False; char *pdata = *ppdata; uint32 flags = 0; @@ -6592,8 +6790,7 @@ static NTSTATUS smb_posix_open(connection_struct *conn, return smb_posix_mkdir(conn, req, ppdata, total_data, - fname, - psbuf, + smb_fname, pdata_return_size); } @@ -6632,11 +6829,10 @@ static NTSTATUS smb_posix_open(connection_struct *conn, raw_unixmode = IVAL(pdata,8); /* Next 4 bytes are not yet defined. */ - status = unix_perms_from_wire(conn, - psbuf, - raw_unixmode, - VALID_STAT(*psbuf) ? PERM_EXISTING_FILE : PERM_NEW_FILE, - &unixmode); + status = unix_perms_from_wire(conn, &smb_fname->st, raw_unixmode, + (VALID_STAT(smb_fname->st) ? + PERM_EXISTING_FILE : PERM_NEW_FILE), + &unixmode); if (!NT_STATUS_IS_OK(status)) { return status; @@ -6655,16 +6851,10 @@ static NTSTATUS smb_posix_open(connection_struct *conn, } DEBUG(10,("smb_posix_open: file %s, smb_posix_flags = %u, mode 0%o\n", - fname, + smb_fname_str_dbg(smb_fname), (unsigned int)wire_open_mode, (unsigned int)unixmode )); - status = create_synthetic_smb_fname_split(talloc_tos(), fname, psbuf, - &smb_fname); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - status = SMB_VFS_CREATE_FILE( conn, /* conn */ req, /* req */ @@ -6683,9 +6873,6 @@ static NTSTATUS smb_posix_open(connection_struct *conn, &fsp, /* result */ &info); /* pinfo */ - *psbuf = smb_fname->st; - TALLOC_FREE(smb_fname); - if (!NT_STATUS_IS_OK(status)) { return status; } @@ -6738,12 +6925,14 @@ static NTSTATUS smb_posix_open(connection_struct *conn, case SMB_QUERY_FILE_UNIX_BASIC: SSVAL(pdata,8,SMB_QUERY_FILE_UNIX_BASIC); SSVAL(pdata,10,0); /* padding. */ - store_file_unix_basic(conn, pdata + 12, fsp, psbuf); + store_file_unix_basic(conn, pdata + 12, fsp, + &smb_fname->st); break; case SMB_QUERY_FILE_UNIX_INFO2: SSVAL(pdata,8,SMB_QUERY_FILE_UNIX_INFO2); SSVAL(pdata,10,0); /* padding. */ - store_file_unix_basic_info2(conn, pdata + 12, fsp, psbuf); + store_file_unix_basic_info2(conn, pdata + 12, fsp, + &smb_fname->st); break; default: SSVAL(pdata,8,SMB_NO_INFO_LEVEL_RETURNED); @@ -6826,7 +7015,7 @@ static NTSTATUS smb_posix_unlink(connection_struct *conn, NULL); if (lck == NULL) { DEBUG(0, ("smb_posix_unlink: Could not get share mode " - "lock for file %s\n", fsp->fsp_name)); + "lock for file %s\n", fsp_str_dbg(fsp))); close_file(req, fsp, NORMAL_CLOSE); return NT_STATUS_INVALID_PARAMETER; } @@ -6867,200 +7056,42 @@ static NTSTATUS smb_posix_unlink(connection_struct *conn, return close_file(req, fsp, NORMAL_CLOSE); } -/**************************************************************************** - Reply to a TRANS2_SETFILEINFO (set file info by fileid or pathname). -****************************************************************************/ - -static void call_trans2setfilepathinfo(connection_struct *conn, - struct smb_request *req, - unsigned int tran_call, - char **pparams, int total_params, - char **ppdata, int total_data, - unsigned int max_data_bytes) +NTSTATUS smbd_do_setfilepathinfo(connection_struct *conn, + struct smb_request *req, + TALLOC_CTX *mem_ctx, + uint16_t info_level, + files_struct *fsp, + struct smb_filename *smb_fname, + char **ppdata, int total_data, + int *ret_data_size) { - char *params = *pparams; char *pdata = *ppdata; - uint16 info_level; - SMB_STRUCT_STAT sbuf; char *fname = NULL; - struct smb_filename *smb_fname = NULL; - files_struct *fsp = NULL; NTSTATUS status = NT_STATUS_OK; int data_return_size = 0; - TALLOC_CTX *ctx = talloc_tos(); - - if (!params) { - reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - return; - } - - if (tran_call == TRANSACT2_SETFILEINFO) { - if (total_params < 4) { - reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - return; - } - - fsp = file_fsp(req, SVAL(params,0)); - /* Basic check for non-null fsp. */ - if (!check_fsp_open(conn, req, fsp)) { - return; - } - info_level = SVAL(params,2); - - fname = talloc_strdup(talloc_tos(),fsp->fsp_name); - if (!fname) { - reply_nterror(req, NT_STATUS_NO_MEMORY); - return; - } - - status = create_synthetic_smb_fname_split(talloc_tos(), fname, - NULL, &smb_fname); - if (!NT_STATUS_IS_OK(status)) { - reply_nterror(req, status); - return; - } - - if(fsp->is_directory || fsp->fh->fd == -1) { - /* - * This is actually a SETFILEINFO on a directory - * handle (returned from an NT SMB). NT5.0 seems - * to do this call. JRA. - */ - if (INFO_LEVEL_IS_UNIX(info_level)) { - /* Always do lstat for UNIX calls. */ - if (SMB_VFS_LSTAT(conn, smb_fname)) { - DEBUG(3,("call_trans2setfilepathinfo: " - "SMB_VFS_LSTAT of %s failed " - "(%s)\n", - smb_fname_str_dbg(smb_fname), - strerror(errno))); - reply_unixerror(req,ERRDOS,ERRbadpath); - return; - } - } else { - if (SMB_VFS_STAT(conn, smb_fname) != 0) { - DEBUG(3,("call_trans2setfilepathinfo: " - "fileinfo of %s failed (%s)\n", - smb_fname_str_dbg(smb_fname), - strerror(errno))); - reply_unixerror(req,ERRDOS,ERRbadpath); - return; - } - } - } else if (fsp->print_file) { - /* - * Doing a DELETE_ON_CLOSE should cancel a print job. - */ - if ((info_level == SMB_SET_FILE_DISPOSITION_INFO) && CVAL(pdata,0)) { - fsp->fh->private_options |= FILE_DELETE_ON_CLOSE; - - DEBUG(3,("call_trans2setfilepathinfo: Cancelling print job (%s)\n", fsp->fsp_name )); - SSVAL(params,0,0); - send_trans2_replies(conn, req, params, 2, - *ppdata, 0, - max_data_bytes); - return; - } else { - reply_unixerror(req, ERRDOS, ERRbadpath); - return; - } - } else { - /* - * Original code - this is an open file. - */ - if (!check_fsp(conn, req, fsp)) { - return; - } - - if (SMB_VFS_FSTAT(fsp, &smb_fname->st) != 0) { - DEBUG(3,("call_trans2setfilepathinfo: fstat " - "of fnum %d failed (%s)\n", fsp->fnum, - strerror(errno))); - reply_unixerror(req, ERRDOS, ERRbadfid); - return; - } - } - } else { - /* set path info */ - if (total_params < 7) { - reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - return; - } - - info_level = SVAL(params,0); - srvstr_get_path(ctx, params, req->flags2, &fname, ¶ms[6], - total_params - 6, STR_TERMINATE, - &status); - if (!NT_STATUS_IS_OK(status)) { - reply_nterror(req, status); - return; - } - - status = filename_convert(ctx, conn, - req->flags2 & FLAGS2_DFS_PATHNAMES, - fname, - &smb_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); - return; - } - reply_nterror(req, status); - return; - } - - if (INFO_LEVEL_IS_UNIX(info_level)) { - /* - * For CIFS UNIX extensions the target name may not exist. - */ - - /* Always do lstat for UNIX calls. */ - SMB_VFS_LSTAT(conn, smb_fname); - - } else if (!VALID_STAT(smb_fname->st) && - SMB_VFS_STAT(conn, smb_fname)) { - DEBUG(3,("call_trans2setfilepathinfo: SMB_VFS_STAT of " - "%s failed (%s)\n", - smb_fname_str_dbg(smb_fname), - strerror(errno))); - reply_unixerror(req, ERRDOS, ERRbadpath); - return; - } - } - - /* Set sbuf for use below. */ - sbuf = smb_fname->st; + *ret_data_size = 0; if (INFO_LEVEL_IS_UNIX(info_level) && !lp_unix_extensions()) { - reply_nterror(req, NT_STATUS_INVALID_LEVEL); - return; + return NT_STATUS_INVALID_LEVEL; } if (!CAN_WRITE(conn)) { /* Allow POSIX opens. The open path will deny * any non-readonly opens. */ if (info_level != SMB_POSIX_PATH_OPEN) { - reply_doserror(req, ERRSRV, ERRaccess); - return; + return NT_STATUS_DOS(ERRSRV, ERRaccess); } } - DEBUG(3,("call_trans2setfilepathinfo(%d) %s (fnum %d) info_level=%d totdata=%d\n", - tran_call,fname, fsp ? fsp->fnum : -1, info_level,total_data)); - - /* Realloc the parameter size */ - *pparams = (char *)SMB_REALLOC(*pparams,2); - if (*pparams == NULL) { - reply_nterror(req, NT_STATUS_NO_MEMORY); - return; + status = get_full_smb_filename(mem_ctx, smb_fname, &fname); + if (!NT_STATUS_IS_OK(status)) { + return status; } - params = *pparams; - SSVAL(params,0,0); + DEBUG(3,("smbd_do_setfilepathinfo: %s (fnum %d) info_level=%d " + "totdata=%d\n", smb_fname_str_dbg(smb_fname), + fsp ? fsp->fnum : -1, info_level, total_data)); switch (info_level) { @@ -7186,22 +7217,20 @@ static void call_trans2setfilepathinfo(connection_struct *conn, case SMB_SET_FILE_UNIX_LINK: { - if (tran_call != TRANSACT2_SETPATHINFO) { + if (fsp) { /* We must have a pathname for this. */ - reply_nterror(req, NT_STATUS_INVALID_LEVEL); - return; + return NT_STATUS_INVALID_LEVEL; } status = smb_set_file_unix_link(conn, req, pdata, - total_data, fname); + total_data, smb_fname); break; } case SMB_SET_FILE_UNIX_HLINK: { - if (tran_call != TRANSACT2_SETPATHINFO || smb_fname == NULL) { + if (fsp) { /* We must have a pathname for this. */ - reply_nterror(req, NT_STATUS_INVALID_LEVEL); - return; + return NT_STATUS_INVALID_LEVEL; } status = smb_set_file_unix_hlink(conn, req, pdata, total_data, @@ -7224,17 +7253,15 @@ static void call_trans2setfilepathinfo(connection_struct *conn, pdata, total_data, fsp, - fname, - &sbuf); + smb_fname); break; } #endif case SMB_SET_POSIX_LOCK: { - if (tran_call != TRANSACT2_SETFILEINFO) { - reply_nterror(req, NT_STATUS_INVALID_LEVEL); - return; + if (!fsp) { + return NT_STATUS_INVALID_LEVEL; } status = smb_set_posix_lock(conn, req, pdata, total_data, fsp); @@ -7243,27 +7270,24 @@ static void call_trans2setfilepathinfo(connection_struct *conn, case SMB_POSIX_PATH_OPEN: { - if (tran_call != TRANSACT2_SETPATHINFO) { + if (fsp) { /* We must have a pathname for this. */ - reply_nterror(req, NT_STATUS_INVALID_LEVEL); - return; + return NT_STATUS_INVALID_LEVEL; } status = smb_posix_open(conn, req, ppdata, total_data, - fname, - &sbuf, + smb_fname, &data_return_size); break; } case SMB_POSIX_PATH_UNLINK: { - if (tran_call != TRANSACT2_SETPATHINFO) { + if (fsp) { /* We must have a pathname for this. */ - reply_nterror(req, NT_STATUS_INVALID_LEVEL); - return; + return NT_STATUS_INVALID_LEVEL; } status = smb_posix_unlink(conn, req, @@ -7274,10 +7298,196 @@ static void call_trans2setfilepathinfo(connection_struct *conn, } default: - reply_nterror(req, NT_STATUS_INVALID_LEVEL); + return NT_STATUS_INVALID_LEVEL; + } + + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + *ret_data_size = data_return_size; + return NT_STATUS_OK; +} + +/**************************************************************************** + Reply to a TRANS2_SETFILEINFO (set file info by fileid or pathname). +****************************************************************************/ + +static void call_trans2setfilepathinfo(connection_struct *conn, + struct smb_request *req, + unsigned int tran_call, + char **pparams, int total_params, + char **ppdata, int total_data, + unsigned int max_data_bytes) +{ + char *params = *pparams; + char *pdata = *ppdata; + uint16 info_level; + struct smb_filename *smb_fname = NULL; + files_struct *fsp = NULL; + NTSTATUS status = NT_STATUS_OK; + int data_return_size = 0; + + if (!params) { + reply_nterror(req, NT_STATUS_INVALID_PARAMETER); + return; + } + + if (tran_call == TRANSACT2_SETFILEINFO) { + if (total_params < 4) { + reply_nterror(req, NT_STATUS_INVALID_PARAMETER); + return; + } + + fsp = file_fsp(req, SVAL(params,0)); + /* Basic check for non-null fsp. */ + if (!check_fsp_open(conn, req, fsp)) { + return; + } + info_level = SVAL(params,2); + + status = copy_smb_filename(talloc_tos(), fsp->fsp_name, + &smb_fname); + if (!NT_STATUS_IS_OK(status)) { + reply_nterror(req, status); + return; + } + + if(fsp->is_directory || fsp->fh->fd == -1) { + /* + * This is actually a SETFILEINFO on a directory + * handle (returned from an NT SMB). NT5.0 seems + * to do this call. JRA. + */ + if (INFO_LEVEL_IS_UNIX(info_level)) { + /* Always do lstat for UNIX calls. */ + if (SMB_VFS_LSTAT(conn, smb_fname)) { + DEBUG(3,("call_trans2setfilepathinfo: " + "SMB_VFS_LSTAT of %s failed " + "(%s)\n", + smb_fname_str_dbg(smb_fname), + strerror(errno))); + reply_nterror(req, map_nt_error_from_unix(errno)); + return; + } + } else { + if (SMB_VFS_STAT(conn, smb_fname) != 0) { + DEBUG(3,("call_trans2setfilepathinfo: " + "fileinfo of %s failed (%s)\n", + smb_fname_str_dbg(smb_fname), + strerror(errno))); + reply_nterror(req, map_nt_error_from_unix(errno)); + return; + } + } + } else if (fsp->print_file) { + /* + * Doing a DELETE_ON_CLOSE should cancel a print job. + */ + if ((info_level == SMB_SET_FILE_DISPOSITION_INFO) && CVAL(pdata,0)) { + fsp->fh->private_options |= FILE_DELETE_ON_CLOSE; + + DEBUG(3,("call_trans2setfilepathinfo: " + "Cancelling print job (%s)\n", + fsp_str_dbg(fsp))); + + SSVAL(params,0,0); + send_trans2_replies(conn, req, params, 2, + *ppdata, 0, + max_data_bytes); + return; + } else { + reply_doserror(req, ERRDOS, ERRbadpath); + return; + } + } else { + /* + * Original code - this is an open file. + */ + if (!check_fsp(conn, req, fsp)) { + return; + } + + if (SMB_VFS_FSTAT(fsp, &smb_fname->st) != 0) { + DEBUG(3,("call_trans2setfilepathinfo: fstat " + "of fnum %d failed (%s)\n", fsp->fnum, + strerror(errno))); + reply_nterror(req, map_nt_error_from_unix(errno)); + return; + } + } + } else { + char *fname = NULL; + + /* set path info */ + if (total_params < 7) { + reply_nterror(req, NT_STATUS_INVALID_PARAMETER); return; + } + + info_level = SVAL(params,0); + srvstr_get_path(req, params, req->flags2, &fname, ¶ms[6], + total_params - 6, STR_TERMINATE, + &status); + if (!NT_STATUS_IS_OK(status)) { + reply_nterror(req, status); + return; + } + + status = filename_convert(req, conn, + req->flags2 & FLAGS2_DFS_PATHNAMES, + fname, + &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); + return; + } + reply_nterror(req, status); + return; + } + + if (INFO_LEVEL_IS_UNIX(info_level)) { + /* + * For CIFS UNIX extensions the target name may not exist. + */ + + /* Always do lstat for UNIX calls. */ + SMB_VFS_LSTAT(conn, smb_fname); + + } else if (!VALID_STAT(smb_fname->st) && + SMB_VFS_STAT(conn, smb_fname)) { + DEBUG(3,("call_trans2setfilepathinfo: SMB_VFS_STAT of " + "%s failed (%s)\n", + smb_fname_str_dbg(smb_fname), + strerror(errno))); + reply_nterror(req, map_nt_error_from_unix(errno)); + return; + } + } + + DEBUG(3,("call_trans2setfilepathinfo(%d) %s (fnum %d) info_level=%d " + "totdata=%d\n", tran_call, smb_fname_str_dbg(smb_fname), + fsp ? fsp->fnum : -1, info_level,total_data)); + + /* Realloc the parameter size */ + *pparams = (char *)SMB_REALLOC(*pparams,2); + if (*pparams == NULL) { + reply_nterror(req, NT_STATUS_NO_MEMORY); + return; } + params = *pparams; + SSVAL(params,0,0); + + status = smbd_do_setfilepathinfo(conn, req, req, + info_level, + fsp, + smb_fname, + ppdata, total_data, + &data_return_size); if (!NT_STATUS_IS_OK(status)) { if (open_was_deferred(req->mid)) { /* We have re-scheduled this call. */ @@ -7301,7 +7511,6 @@ static void call_trans2setfilepathinfo(connection_struct *conn, return; } - SSVAL(params,0,0); send_trans2_replies(conn, req, params, 2, *ppdata, data_return_size, max_data_bytes); @@ -7349,8 +7558,7 @@ static void call_trans2mkdir(connection_struct *conn, struct smb_request *req, conn, req->flags2 & FLAGS2_DFS_PATHNAMES, directory, - &smb_dname, - NULL); + &smb_dname); if (!NT_STATUS_IS_OK(status)) { if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { diff --git a/source3/smbd/vfs.c b/source3/smbd/vfs.c index 2b4124bf7b..cd78c7962e 100644 --- a/source3/smbd/vfs.c +++ b/source3/smbd/vfs.c @@ -487,10 +487,12 @@ int vfs_allocate_file_space(files_struct *fsp, uint64_t len) * Actually try and commit the space on disk.... */ - DEBUG(10,("vfs_allocate_file_space: file %s, len %.0f\n", fsp->fsp_name, (double)len )); + DEBUG(10,("vfs_allocate_file_space: file %s, len %.0f\n", + fsp_str_dbg(fsp), (double)len)); if (((SMB_OFF_T)len) < 0) { - DEBUG(0,("vfs_allocate_file_space: %s negative len requested.\n", fsp->fsp_name )); + DEBUG(0,("vfs_allocate_file_space: %s negative len " + "requested.\n", fsp_str_dbg(fsp))); errno = EINVAL; return -1; } @@ -505,8 +507,9 @@ int vfs_allocate_file_space(files_struct *fsp, uint64_t len) if (len < (uint64_t)st.st_ex_size) { /* Shrink - use ftruncate. */ - DEBUG(10,("vfs_allocate_file_space: file %s, shrink. Current size %.0f\n", - fsp->fsp_name, (double)st.st_ex_size )); + DEBUG(10,("vfs_allocate_file_space: file %s, shrink. Current " + "size %.0f\n", fsp_str_dbg(fsp), + (double)st.st_ex_size)); contend_level2_oplocks_begin(fsp, LEVEL2_CONTEND_ALLOC_SHRINK); @@ -530,13 +533,16 @@ int vfs_allocate_file_space(files_struct *fsp, uint64_t len) len -= st.st_ex_size; len /= 1024; /* Len is now number of 1k blocks needed. */ - space_avail = get_dfree_info(conn,fsp->fsp_name,False,&bsize,&dfree,&dsize); + space_avail = get_dfree_info(conn, fsp->fsp_name->base_name, false, + &bsize, &dfree, &dsize); if (space_avail == (uint64_t)-1) { return -1; } - DEBUG(10,("vfs_allocate_file_space: file %s, grow. Current size %.0f, needed blocks = %.0f, space avail = %.0f\n", - fsp->fsp_name, (double)st.st_ex_size, (double)len, (double)space_avail )); + DEBUG(10,("vfs_allocate_file_space: file %s, grow. Current size %.0f, " + "needed blocks = %.0f, space avail = %.0f\n", + fsp_str_dbg(fsp), (double)st.st_ex_size, (double)len, + (double)space_avail)); if (len > space_avail) { errno = ENOSPC; @@ -558,14 +564,15 @@ int vfs_set_filelen(files_struct *fsp, SMB_OFF_T len) contend_level2_oplocks_begin(fsp, LEVEL2_CONTEND_SET_FILE_LEN); - DEBUG(10,("vfs_set_filelen: ftruncate %s to len %.0f\n", fsp->fsp_name, (double)len)); + DEBUG(10,("vfs_set_filelen: ftruncate %s to len %.0f\n", + fsp_str_dbg(fsp), (double)len)); flush_write_cache(fsp, SIZECHANGE_FLUSH); if ((ret = SMB_VFS_FTRUNCATE(fsp, len)) != -1) { set_filelen_write_cache(fsp, len); notify_fname(fsp->conn, NOTIFY_ACTION_MODIFIED, FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_ATTRIBUTES, - fsp->fsp_name); + fsp->fsp_name->base_name); } contend_level2_oplocks_end(fsp, LEVEL2_CONTEND_SET_FILE_LEN); @@ -600,8 +607,10 @@ int vfs_fill_sparse(files_struct *fsp, SMB_OFF_T len) return 0; } - DEBUG(10,("vfs_fill_sparse: write zeros in file %s from len %.0f to len %.0f (%.0f bytes)\n", - fsp->fsp_name, (double)st.st_ex_size, (double)len, (double)(len - st.st_ex_size))); + DEBUG(10,("vfs_fill_sparse: write zeros in file %s from len %.0f to " + "len %.0f (%.0f bytes)\n", fsp_str_dbg(fsp), + (double)st.st_ex_size, (double)len, + (double)(len - st.st_ex_size))); contend_level2_oplocks_begin(fsp, LEVEL2_CONTEND_FILL_SPARSE); @@ -625,8 +634,9 @@ int vfs_fill_sparse(files_struct *fsp, SMB_OFF_T len) pwrite_ret = SMB_VFS_PWRITE(fsp, sparse_buf, curr_write_size, offset + total); if (pwrite_ret == -1) { - DEBUG(10,("vfs_fill_sparse: SMB_VFS_PWRITE for file %s failed with error %s\n", - fsp->fsp_name, strerror(errno) )); + DEBUG(10,("vfs_fill_sparse: SMB_VFS_PWRITE for file " + "%s failed with error %s\n", + fsp_str_dbg(fsp), strerror(errno))); ret = -1; goto out; } @@ -962,15 +972,28 @@ NTSTATUS check_reduced_name(connection_struct *conn, const char *fname) #ifdef S_ISLNK if (!lp_symlinks(SNUM(conn))) { - SMB_STRUCT_STAT statbuf; - if ( (vfs_lstat_smb_fname(conn,fname,&statbuf) != -1) && - (S_ISLNK(statbuf.st_ex_mode)) ) { + struct smb_filename *smb_fname = NULL; + NTSTATUS status; + + status = create_synthetic_smb_fname(talloc_tos(), fname, NULL, + NULL, &smb_fname); + if (!NT_STATUS_IS_OK(status)) { + if (free_resolved_name) { + SAFE_FREE(resolved_name); + } + return status; + } + + if ( (SMB_VFS_LSTAT(conn, smb_fname) != -1) && + (S_ISLNK(smb_fname->st.st_ex_mode)) ) { if (free_resolved_name) { SAFE_FREE(resolved_name); } DEBUG(3,("reduce_name: denied: file path name %s is a symlink\n",resolved_name)); + TALLOC_FREE(smb_fname); return NT_STATUS_ACCESS_DENIED; } + TALLOC_FREE(smb_fname); } #endif @@ -980,3 +1003,58 @@ NTSTATUS check_reduced_name(connection_struct *conn, const char *fname) } return NT_STATUS_OK; } + +/** + * XXX: This is temporary and there should be no callers of this once + * smb_filename is plumbed through all path based operations. + */ +int vfs_stat_smb_fname(struct connection_struct *conn, const char *fname, + SMB_STRUCT_STAT *psbuf) +{ + struct smb_filename *smb_fname = NULL; + NTSTATUS status; + int ret; + + status = create_synthetic_smb_fname_split(talloc_tos(), fname, NULL, + &smb_fname); + if (!NT_STATUS_IS_OK(status)) { + errno = map_errno_from_nt_status(status); + return -1; + } + + ret = SMB_VFS_STAT(conn, smb_fname); + if (ret != -1) { + *psbuf = smb_fname->st; + } + + TALLOC_FREE(smb_fname); + return ret; +} + +/** + * XXX: This is temporary and there should be no callers of this once + * smb_filename is plumbed through all path based operations. + */ +int vfs_lstat_smb_fname(struct connection_struct *conn, const char *fname, + SMB_STRUCT_STAT *psbuf) +{ + struct smb_filename *smb_fname = NULL; + NTSTATUS status; + int ret; + + status = create_synthetic_smb_fname_split(talloc_tos(), fname, NULL, + &smb_fname); + if (!NT_STATUS_IS_OK(status)) { + errno = map_errno_from_nt_status(status); + return -1; + } + + ret = SMB_VFS_LSTAT(conn, smb_fname); + if (ret != -1) { + *psbuf = smb_fname->st; + } + + TALLOC_FREE(smb_fname); + return ret; +} + |