diff options
-rw-r--r-- | source3/smbd/trans2.c | 404 |
1 files changed, 216 insertions, 188 deletions
diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c index 6554fb67b7..54d873065c 100644 --- a/source3/smbd/trans2.c +++ b/source3/smbd/trans2.c @@ -7055,200 +7055,45 @@ 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) +static 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_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->fsp_name )); - - 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 { - /* 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_nterror(req, map_nt_error_from_unix(errno)); - return; - } - } + *ret_data_size = 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; } 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", + fname, fsp ? fsp->fnum : -1, info_level, total_data)); switch (info_level) { @@ -7374,10 +7219,9 @@ 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); @@ -7386,10 +7230,9 @@ static void call_trans2setfilepathinfo(connection_struct *conn, case SMB_SET_FILE_UNIX_HLINK: { - if (tran_call != TRANSACT2_SETPATHINFO || smb_fname == NULL) { + if (fsp || smb_fname == NULL) { /* 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, @@ -7420,9 +7263,8 @@ static void call_trans2setfilepathinfo(connection_struct *conn, 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); @@ -7431,10 +7273,9 @@ 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, @@ -7448,10 +7289,9 @@ static void call_trans2setfilepathinfo(connection_struct *conn, 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, @@ -7462,10 +7302,199 @@ 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; + char *fname = NULL; + 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); + + 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_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->fsp_name )); + + 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 { + /* 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, + &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, 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. */ @@ -7489,7 +7518,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); |