return val;
}
+/********************************************************************
+ Create a 64 bit FileIndex. If the file is on the same device as
+ the root of the share, just return the 64-bit inode. If it isn't,
+ mangle as we used to do.
+********************************************************************/
+
+uint64_t get_FileIndex(connection_struct *conn, const SMB_STRUCT_STAT *psbuf)
+{
+ uint64_t file_index;
+ if (conn->base_share_dev == psbuf->st_ex_dev) {
+ return (uint64_t)psbuf->st_ex_ino;
+ }
+ file_index = ((psbuf->st_ex_ino) & UINT32_MAX); /* FileIndexLow */
+ file_index |= ((uint64_t)((psbuf->st_ex_dev) & UINT32_MAX)) << 32; /* FileIndexHigh */
+ return file_index;
+}
+
/****************************************************************************
Utility functions for dealing with extended attributes.
****************************************************************************/
reply_outbuf(req, 10, total_sent_thistime + alignment_offset
+ data_alignment_offset);
- /*
- * We might have SMBtrans2s in req which was transferred to
- * the outbuf, fix that.
- */
- SCVAL(req->outbuf, smb_com, SMBtrans2);
-
/* Set total params and data to be sent */
SSVAL(req->outbuf,smb_tprcnt,paramsize);
SSVAL(req->outbuf,smb_tdrcnt,datasize);
pname = ¶ms[28];
if (IS_IPC(conn)) {
- reply_doserror(req, ERRSRV, ERRaccess);
+ reply_nterror(req, NT_STATUS_NETWORK_ACCESS_DENIED);
goto out;
}
goto out;
}
- if (!map_open_params_to_ntcreate(smb_fname, deny_mode, open_ofun,
+ if (!map_open_params_to_ntcreate(smb_fname->base_name, deny_mode,
+ open_ofun,
&access_mask, &share_mode,
&create_disposition,
&create_options)) {
- reply_doserror(req, ERRDOS, ERRbadaccess);
+ reply_nterror(req, NT_STATUS_ACCESS_DENIED);
goto out;
}
/* Any data in this call is an EA list. */
- if (total_data && (total_data != 4) && !lp_ea_support(SNUM(conn))) {
- reply_nterror(req, NT_STATUS_EAS_NOT_SUPPORTED);
- goto out;
- }
-
- if (total_data != 4) {
+ if (total_data && (total_data != 4)) {
if (total_data < 10) {
reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
goto out;
reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
goto out;
}
- } else if (IVAL(pdata,0) != 4) {
- reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
- goto out;
+
+ if (!lp_ea_support(SNUM(conn))) {
+ reply_nterror(req, NT_STATUS_EAS_NOT_SUPPORTED);
+ goto out;
+ }
}
status = SMB_VFS_CREATE_FILE(
inode = smb_fname->st.st_ex_ino;
if (fattr & aDIR) {
close_file(req, fsp, ERROR_CLOSE);
- reply_doserror(req, ERRDOS,ERRnoaccess);
+ reply_nterror(req, NT_STATUS_ACCESS_DENIED);
goto out;
}
uint32_t reskey=0;
uint64_t file_size = 0;
uint64_t allocation_size = 0;
+ uint64_t file_index = 0;
uint32_t len;
struct timespec mdate_ts, adate_ts, cdate_ts, create_date_ts;
time_t mdate = (time_t)0, adate = (time_t)0, create_date = (time_t)0;
char *nameptr;
char *last_entry_ptr;
bool was_8_3;
- uint32_t nt_extmode; /* Used for NT connections instead of mode */
off_t off;
off_t pad = 0;
}
allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn, NULL, &smb_fname->st);
+ file_index = get_FileIndex(conn, &smb_fname->st);
+
mdate_ts = smb_fname->st.st_ex_mtime;
adate_ts = smb_fname->st.st_ex_atime;
create_date_ts = get_create_timespec(conn, NULL, smb_fname);
pad = 0;
off = 0;
- nt_extmode = mode ? mode : FILE_ATTRIBUTE_NORMAL;
-
switch (info_level) {
case SMB_FIND_INFO_STANDARD:
DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_INFO_STANDARD\n"));
put_long_date_timespec(conn->ts_res,p,cdate_ts); p += 8;
SOFF_T(p,0,file_size); p += 8;
SOFF_T(p,0,allocation_size); p += 8;
- SIVAL(p,0,nt_extmode); p += 4;
+ SIVAL(p,0,mode); p += 4;
q = p; p += 4; /* q is placeholder for name length. */
{
unsigned int ea_size = estimate_ea_size(conn, NULL,
put_long_date_timespec(conn->ts_res,p,cdate_ts); p += 8;
SOFF_T(p,0,file_size); p += 8;
SOFF_T(p,0,allocation_size); p += 8;
- SIVAL(p,0,nt_extmode); p += 4;
+ SIVAL(p,0,mode); p += 4;
len = srvstr_push(base_data, flags2,
p + 4, fname, PTR_DIFF(end_data, p+4),
STR_TERMINATE_ASCII);
put_long_date_timespec(conn->ts_res,p,cdate_ts); p += 8;
SOFF_T(p,0,file_size); p += 8;
SOFF_T(p,0,allocation_size); p += 8;
- SIVAL(p,0,nt_extmode); p += 4;
+ SIVAL(p,0,mode); p += 4;
q = p; p += 4; /* q is placeholder for name length. */
{
unsigned int ea_size = estimate_ea_size(conn, NULL,
put_long_date_timespec(conn->ts_res,p,cdate_ts); p += 8;
SOFF_T(p,0,file_size); p += 8;
SOFF_T(p,0,allocation_size); p += 8;
- SIVAL(p,0,nt_extmode); p += 4;
+ SIVAL(p,0,mode); p += 4;
q = p; p += 4; /* q is placeholder for name length. */
{
unsigned int ea_size = estimate_ea_size(conn, NULL,
p +=4;
}
SIVAL(p,0,0); p += 4; /* Unknown - reserved ? */
- SIVAL(p,0,smb_fname->st.st_ex_ino); p += 4; /* FileIndexLow */
- SIVAL(p,0,smb_fname->st.st_ex_dev); p += 4; /* FileIndexHigh */
+ SBVAL(p,0,file_index); p += 8;
len = srvstr_push(base_data, flags2, p,
fname, PTR_DIFF(end_data, p),
STR_TERMINATE_ASCII);
put_long_date_timespec(conn->ts_res,p,cdate_ts); p += 8;
SOFF_T(p,0,file_size); p += 8;
SOFF_T(p,0,allocation_size); p += 8;
- SIVAL(p,0,nt_extmode); p += 4;
+ SIVAL(p,0,mode); p += 4;
q = p; p += 4; /* q is placeholder for name length */
{
unsigned int ea_size = estimate_ea_size(conn, NULL,
}
p += 26;
SSVAL(p,0,0); p += 2; /* Reserved ? */
- SIVAL(p,0,smb_fname->st.st_ex_ino); p += 4; /* FileIndexLow */
- SIVAL(p,0,smb_fname->st.st_ex_dev); p += 4; /* FileIndexHigh */
+ SBVAL(p,0,file_index); p += 8;
len = srvstr_push(base_data, flags2, p,
fname, PTR_DIFF(end_data, p),
STR_TERMINATE_ASCII);
TALLOC_CTX *ctx = talloc_tos();
struct dptr_struct *dirptr = NULL;
struct smbd_server_connection *sconn = smbd_server_conn;
+ uint32_t ucf_flags = (UCF_SAVE_LCOMP | UCF_ALWAYS_ALLOW_WCARD_LCOMP);
if (total_params < 13) {
reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
reply_nterror(req, NT_STATUS_INVALID_LEVEL);
goto out;
}
+ ucf_flags |= UCF_UNIX_NAME_LOOKUP;
break;
default:
reply_nterror(req, NT_STATUS_INVALID_LEVEL);
ntstatus = filename_convert(ctx, conn,
req->flags2 & FLAGS2_DFS_PATHNAMES,
directory,
- (UCF_SAVE_LCOMP |
- UCF_ALWAYS_ALLOW_WCARD_LCOMP),
+ ucf_flags,
&mask_contains_wcard,
&smb_dname);
if (!NT_STATUS_IS_OK(ntstatus)) {
}
if (!lp_ea_support(SNUM(conn))) {
- reply_doserror(req, ERRDOS, ERReasnotsupported);
+ reply_nterror(req, NT_STATUS_EAS_NOT_SUPPORTED);
goto out;
}
if(numentries == 0) {
dptr_close(sconn, &dptr_num);
if (get_Protocol() < PROTOCOL_NT1) {
- reply_doserror(req, ERRDOS, ERRnofiles);
+ reply_force_doserror(req, ERRDOS, ERRnofiles);
goto out;
} else {
reply_botherror(req, NT_STATUS_NO_SUCH_FILE,
}
if (!lp_ea_support(SNUM(conn))) {
- reply_doserror(req, ERRDOS, ERReasnotsupported);
+ reply_nterror(req, NT_STATUS_EAS_NOT_SUPPORTED);
return;
}
/* Check that the dptr is valid */
if(!(dirptr = dptr_fetch_lanman2(sconn, dptr_num))) {
- reply_doserror(req, ERRDOS, ERRnofiles);
+ reply_nterror(req, STATUS_NO_MORE_FILES);
return;
}
/* Get the wildcard mask from the dptr */
if((p = dptr_wcard(sconn, dptr_num))== NULL) {
DEBUG(2,("dptr_num %d has no wildcard\n", dptr_num));
- reply_doserror(req, ERRDOS, ERRnofiles);
+ reply_nterror(req, STATUS_NO_MORE_FILES);
return;
}
fsp.fnum = -1;
/* access check */
- if (conn->server_info->utok.uid != sec_initial_uid()) {
+ if (conn->server_info->utok.uid != sec_initial_uid() &&
+ !conn->admin_user) {
DEBUG(0,("set_user_quota: access_denied "
"service [%s] user [%s]\n",
lp_servicename(SNUM(conn)),
ZERO_STRUCT(quotas);
/* access check */
- if ((conn->server_info->utok.uid != sec_initial_uid())
+ if (((conn->server_info->utok.uid != sec_initial_uid()) && !conn->admin_user)
||!CAN_WRITE(conn)) {
DEBUG(0,("set_user_quota: access_denied service [%s] user [%s]\n",
lp_servicename(SNUM(conn)),
files_struct *fsp,
const SMB_STRUCT_STAT *psbuf)
{
+ uint64_t file_index = get_FileIndex(conn, psbuf);
+
DEBUG(10,("store_file_unix_basic: SMB_QUERY_FILE_UNIX_BASIC\n"));
DEBUG(4,("store_file_unix_basic: st_mode=%o\n",(int)psbuf->st_ex_mode));
SIVAL(pdata,4,0);
pdata += 8;
- SINO_T_VAL(pdata,0,(SMB_INO_T)psbuf->st_ex_ino); /* inode number */
+ SINO_T_VAL(pdata,0,(SMB_INO_T)file_index); /* inode number */
pdata += 8;
SIVAL(pdata,0, unix_perms_to_wire(psbuf->st_ex_mode)); /* Standard UNIX file permissions */
} else {
mode = dos_mode(conn, smb_fname);
}
- if (!mode)
- mode = FILE_ATTRIBUTE_NORMAL;
nlink = psbuf->st_ex_nlink;
I think this causes us to fail the IFSKIT
BasicFileInformationTest. -tpot */
- file_index = ((psbuf->st_ex_ino) & UINT32_MAX); /* FileIndexLow */
- file_index |= ((uint64_t)((psbuf->st_ex_dev) & UINT32_MAX)) << 32; /* FileIndexHigh */
+ file_index = get_FileIndex(conn, psbuf);
switch (info_level) {
case SMB_INFO_STANDARD:
} else {
char *fname = NULL;
+ uint32_t ucf_flags = 0;
/* qpathinfo */
if (total_params < 7) {
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;
+ if (INFO_LEVEL_IS_UNIX(info_level)) {
+ if (!lp_unix_extensions()) {
+ reply_nterror(req, NT_STATUS_INVALID_LEVEL);
+ return;
+ }
+ if (info_level == SMB_QUERY_FILE_UNIX_BASIC ||
+ info_level == SMB_QUERY_FILE_UNIX_INFO2 ||
+ info_level == SMB_QUERY_FILE_UNIX_LINK) {
+ ucf_flags |= UCF_UNIX_NAME_LOOKUP;
+ }
}
srvstr_get_path(req, params, req->flags2, &fname, ¶ms[6],
conn,
req->flags2 & FLAGS2_DFS_PATHNAMES,
fname,
- 0,
+ ucf_flags,
NULL,
&smb_fname);
if (!NT_STATUS_IS_OK(status)) {
}
if (!lp_ea_support(SNUM(conn))) {
- reply_doserror(req, ERRDOS,
- ERReasnotsupported);
+ reply_nterror(req, NT_STATUS_EAS_NOT_SUPPORTED);
return;
}
(unsigned int)dosmode,
(unsigned int)delete_on_close ));
- status = can_set_delete_on_close(fsp, delete_on_close, dosmode);
-
- if (!NT_STATUS_IS_OK(status)) {
- return status;
+ if (delete_on_close) {
+ status = can_set_delete_on_close(fsp, dosmode);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
}
/* The set is across all open files on this dev/inode pair. */
{
char *link_target = NULL;
const char *newname = smb_fname->base_name;
- NTSTATUS status = NT_STATUS_OK;
TALLOC_CTX *ctx = talloc_tos();
/* Set a symbolic link. */
return NT_STATUS_INVALID_PARAMETER;
}
- /* !widelinks forces the target path to be within the share. */
- /* This means we can interpret the target as a pathname. */
- if (!lp_widelinks(SNUM(conn))) {
- char *rel_name = NULL;
- char *last_dirp = NULL;
-
- if (*link_target == '/') {
- /* No absolute paths allowed. */
- return NT_STATUS_ACCESS_DENIED;
- }
- rel_name = talloc_strdup(ctx,newname);
- if (!rel_name) {
- return NT_STATUS_NO_MEMORY;
- }
- last_dirp = strrchr_m(rel_name, '/');
- if (last_dirp) {
- last_dirp[1] = '\0';
- } else {
- rel_name = talloc_strdup(ctx,"./");
- if (!rel_name) {
- return NT_STATUS_NO_MEMORY;
- }
- }
- rel_name = talloc_asprintf_append(rel_name,
- "%s",
- link_target);
- if (!rel_name) {
- return NT_STATUS_NO_MEMORY;
- }
-
- status = check_name(conn, rel_name);
- if (!NT_STATUS_IS_OK(status)) {
- return status;
- }
- }
-
DEBUG(10,("smb_set_file_unix_link: SMB_SET_FILE_UNIX_LINK doing symlink %s -> %s\n",
newname, link_target ));
status = resolve_dfspath_wcard(ctx, conn,
req->flags2 & FLAGS2_DFS_PATHNAMES,
newname,
+ true,
&newname,
&dest_has_wcard);
if (!NT_STATUS_IS_OK(status)) {
files_struct *all_fsps = NULL;
bool modify_mtime = true;
struct file_id id;
+ struct smb_filename *smb_fname_tmp = NULL;
SMB_STRUCT_STAT sbuf;
ZERO_STRUCT(ft);
sbuf = smb_fname->st;
if (!VALID_STAT(sbuf)) {
- struct smb_filename *smb_fname_tmp = NULL;
/*
* The only valid use of this is to create character and block
* devices, and named pipes. This is deprecated (IMHO) and
}
sbuf = smb_fname_tmp->st;
- TALLOC_FREE(smb_fname_tmp);
+ smb_fname = smb_fname_tmp;
/* Ensure we don't try and change anything else. */
raw_unixmode = SMB_MODE_NO_CHANGE;
wire_open_mode &= ~SMB_ACCMODE;
- if((wire_open_mode & (SMB_O_CREAT | SMB_O_EXCL)) == (SMB_O_CREAT | SMB_O_EXCL)) {
- create_disp = FILE_CREATE;
- } else if((wire_open_mode & (SMB_O_CREAT | SMB_O_TRUNC)) == (SMB_O_CREAT | SMB_O_TRUNC)) {
- create_disp = FILE_OVERWRITE_IF;
- } else if((wire_open_mode & SMB_O_CREAT) == SMB_O_CREAT) {
- create_disp = FILE_OPEN_IF;
- } else if ((wire_open_mode & (SMB_O_CREAT | SMB_O_EXCL | SMB_O_TRUNC)) == 0) {
- create_disp = FILE_OPEN;
- } else {
- DEBUG(5,("smb_posix_open: invalid create mode 0x%x\n",
- (unsigned int)wire_open_mode ));
- return NT_STATUS_INVALID_PARAMETER;
+ /* First take care of O_CREAT|O_EXCL interactions. */
+ switch (wire_open_mode & (SMB_O_CREAT | SMB_O_EXCL)) {
+ case (SMB_O_CREAT | SMB_O_EXCL):
+ /* File exists fail. File not exist create. */
+ create_disp = FILE_CREATE;
+ break;
+ case SMB_O_CREAT:
+ /* File exists open. File not exist create. */
+ create_disp = FILE_OPEN_IF;
+ break;
+ case 0:
+ /* File exists open. File not exist fail. */
+ create_disp = FILE_OPEN;
+ break;
+ case SMB_O_EXCL:
+ /* O_EXCL on its own without O_CREAT is undefined. */
+ default:
+ DEBUG(5,("smb_posix_open: invalid create mode 0x%x\n",
+ (unsigned int)wire_open_mode ));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ /* Next factor in the effects of O_TRUNC. */
+ wire_open_mode &= ~(SMB_O_CREAT | SMB_O_EXCL);
+
+ if (wire_open_mode & SMB_O_TRUNC) {
+ switch (create_disp) {
+ case FILE_CREATE:
+ /* (SMB_O_CREAT | SMB_O_EXCL | O_TRUNC) */
+ /* Leave create_disp alone as
+ (O_CREAT|O_EXCL|O_TRUNC) == (O_CREAT|O_EXCL)
+ */
+ /* File exists fail. File not exist create. */
+ break;
+ case FILE_OPEN_IF:
+ /* SMB_O_CREAT | SMB_O_TRUNC */
+ /* File exists overwrite. File not exist create. */
+ create_disp = FILE_OVERWRITE_IF;
+ break;
+ case FILE_OPEN:
+ /* SMB_O_TRUNC */
+ /* File exists overwrite. File not exist fail. */
+ create_disp = FILE_OVERWRITE;
+ break;
+ default:
+ /* Cannot get here. */
+ smb_panic("smb_posix_open: logic error");
+ return NT_STATUS_INVALID_PARAMETER;
+ }
}
raw_unixmode = IVAL(pdata,8);
max_data_bytes);
return;
} else {
- reply_doserror(req, ERRDOS, ERRbadpath);
+ reply_nterror(req,
+ NT_STATUS_OBJECT_PATH_NOT_FOUND);
return;
}
} else {
}
} else {
char *fname = NULL;
+ uint32_t ucf_flags = 0;
/* set path info */
if (total_params < 7) {
return;
}
+ if (info_level == SMB_SET_FILE_UNIX_BASIC ||
+ info_level == SMB_SET_FILE_UNIX_INFO2 ||
+ info_level == SMB_FILE_RENAME_INFORMATION ||
+ info_level == SMB_POSIX_PATH_UNLINK) {
+ ucf_flags |= UCF_UNIX_NAME_LOOKUP;
+ }
+
status = filename_convert(req, conn,
req->flags2 & FLAGS2_DFS_PATHNAMES,
fname,
- 0,
+ ucf_flags,
NULL,
&smb_fname);
if (!NT_STATUS_IS_OK(status)) {
TALLOC_CTX *ctx = talloc_tos();
if (!CAN_WRITE(conn)) {
- reply_doserror(req, ERRSRV, ERRaccess);
+ reply_nterror(req, NT_STATUS_ACCESS_DENIED);
return;
}
return;
}
- /* Any data in this call is an EA list. */
- if (total_data && (total_data != 4) && !lp_ea_support(SNUM(conn))) {
- reply_nterror(req, NT_STATUS_EAS_NOT_SUPPORTED);
- goto out;
- }
-
/*
* OS/2 workplace shell seems to send SET_EA requests of "null"
* length (4 bytes containing IVAL 4).
* They seem to have no effect. Bug #3212. JRA.
*/
- if (total_data != 4) {
+ if (total_data && (total_data != 4)) {
+ /* Any data in this call is an EA list. */
if (total_data < 10) {
reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
goto out;
reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
goto out;
}
+
+ if (!lp_ea_support(SNUM(conn))) {
+ reply_nterror(req, NT_STATUS_EAS_NOT_SUPPORTED);
+ goto out;
+ }
}
/* If total_data == 4 Windows doesn't care what values
* are placed in that field, it just ignores them.
max_referral_level = SVAL(params,0);
if(!lp_host_msdfs()) {
- reply_doserror(req, ERRDOS, ERRbadfunc);
+ reply_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
return;
}
/* check for an invalid fid before proceeding */
if (!fsp) {
- reply_doserror(req, ERRDOS, ERRbadfid);
+ reply_nterror(req, NT_STATUS_INVALID_HANDLE);
return;
}
}
DEBUG(2,("Unknown TRANS2_IOCTL\n"));
- reply_doserror(req, ERRSRV, ERRerror);
+ reply_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
}
/****************************************************************************
default:
/* Error in request */
DEBUG(2,("Unknown request %d in trans2 call\n", state->call));
- reply_doserror(req, ERRSRV,ERRerror);
+ reply_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
}
}
case TRANSACT2_SETFSINFO:
break;
default:
- reply_doserror(req, ERRSRV, ERRaccess);
+ reply_nterror(req, NT_STATUS_ACCESS_DENIED);
END_PROFILE(SMBtrans2);
return;
}
show_msg((char *)req->inbuf);
+ /* Windows clients expect all replies to
+ a transact secondary (SMBtranss2 0x33)
+ to have a command code of transact
+ (SMBtrans2 0x32). See bug #8989
+ and also [MS-CIFS] section 2.2.4.47.2
+ for details.
+ */
+ req->cmd = SMBtrans2;
+
if (req->wct < 8) {
reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
END_PROFILE(SMBtranss2);