summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source3/smbd/trans2.c393
-rw-r--r--source3/smbd/vfs.c1
2 files changed, 219 insertions, 175 deletions
diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c
index 98ea6c111a..826ccd3f92 100644
--- a/source3/smbd/trans2.c
+++ b/source3/smbd/trans2.c
@@ -4211,7 +4211,9 @@ static NTSTATUS smb_set_posix_lock(connection_struct *conn,
Deal with SMB_INFO_STANDARD.
****************************************************************************/
-static NTSTATUS smb_set_info_standard(const char *pdata, int total_data, struct utimbuf *p_tvs)
+static NTSTATUS smb_set_info_standard(const char *pdata,
+ int total_data,
+ struct utimbuf *p_tvs)
{
if (total_data < 12) {
return NT_STATUS_INVALID_PARAMETER;
@@ -4228,7 +4230,10 @@ static NTSTATUS smb_set_info_standard(const char *pdata, int total_data, struct
Deal with SMB_SET_FILE_BASIC_INFO.
****************************************************************************/
-static NTSTATUS smb_set_file_basic_info(const char *pdata, int total_data, struct utimbuf *p_tvs, int *p_dosmode)
+static NTSTATUS smb_set_file_basic_info(const char *pdata,
+ int total_data,
+ struct utimbuf *p_tvs,
+ int *p_dosmode)
{
/* Patch to do this correctly from Paul Eggert <eggert@twinsun.com>. */
time_t write_time;
@@ -4273,7 +4278,6 @@ static NTSTATUS smb_set_file_allocation_info(connection_struct *conn,
SMB_STRUCT_STAT *psbuf,
SMB_OFF_T *p_size)
{
- int ret = -1;
SMB_BIG_UINT allocation_size;
if (total_data < 8) {
@@ -4298,6 +4302,7 @@ static NTSTATUS smb_set_file_allocation_info(connection_struct *conn,
}
if(allocation_size != get_file_size(*psbuf)) {
+ int ret = -1;
SMB_STRUCT_STAT new_sbuf;
DEBUG(10,("smb_set_file_allocation_info: file %s : setting new allocation size to %.0f\n",
@@ -4306,10 +4311,13 @@ static NTSTATUS smb_set_file_allocation_info(connection_struct *conn,
if (fsp && fsp->fh->fd != -1) {
/* Open file. */
ret = vfs_allocate_file_space(fsp, allocation_size);
+ if (ret == -1) {
+ return map_nt_error_from_unix(errno);
+ }
if (SMB_VFS_FSTAT(fsp,fsp->fh->fd,&new_sbuf) != 0) {
DEBUG(3,("smb_set_file_allocation_info: fstat of fnum %d failed (%s)\n",
fsp->fnum, strerror(errno)));
- ret = -1;
+ return map_nt_error_from_unix(errno);
}
} else {
/* Pathname or stat or directory file. */
@@ -4330,16 +4338,20 @@ static NTSTATUS smb_set_file_allocation_info(connection_struct *conn,
return status;
}
ret = vfs_allocate_file_space(new_fsp, allocation_size);
+ if (ret == -1) {
+ status = map_nt_error_from_unix(errno);
+ close_file(new_fsp,NORMAL_CLOSE);
+ return status;
+ }
if (SMB_VFS_FSTAT(new_fsp,new_fsp->fh->fd,&new_sbuf) != 0) {
DEBUG(3,("smb_set_file_allocation_info: fstat of fnum %d failed (%s)\n",
new_fsp->fnum, strerror(errno)));
- ret = -1;
+ status = map_nt_error_from_unix(errno);
+ close_file(new_fsp,NORMAL_CLOSE);
+ return status;
}
close_file(new_fsp,NORMAL_CLOSE);
}
- if (ret == -1) {
- return NT_STATUS_DISK_FULL;
- }
/* Allocate can truncate size... */
*p_size = get_file_size(new_sbuf);
@@ -4375,6 +4387,190 @@ static NTSTATUS smb_set_file_end_of_file_info(connection_struct *conn,
return NT_STATUS_OK;
}
+/****************************************************************************
+ Deal with SMB_SET_FILE_UNIX_BASIC.
+****************************************************************************/
+
+static NTSTATUS smb_set_file_unix_basic(connection_struct *conn,
+ const char *pdata,
+ int total_data,
+ files_struct *fsp,
+ const char *fname,
+ SMB_STRUCT_STAT *psbuf,
+ SMB_OFF_T *p_size,
+ struct utimbuf *p_tvs,
+ mode_t *p_unixmode,
+ int *p_dosmode)
+{
+ uid_t set_owner = (uid_t)SMB_UID_NO_CHANGE;
+ gid_t set_grp = (uid_t)SMB_GID_NO_CHANGE;
+ uint32 raw_unixmode;
+ BOOL delete_on_fail = False;
+ NTSTATUS status = NT_STATUS_OK;
+
+ if (total_data < 100) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ set_owner = VALID_STAT(*psbuf) ? psbuf->st_uid : (uid_t)SMB_UID_NO_CHANGE;
+ set_grp = VALID_STAT(*psbuf) ? psbuf->st_gid : (gid_t)SMB_GID_NO_CHANGE;
+
+ if(IVAL(pdata, 0) != SMB_SIZE_NO_CHANGE_LO &&
+ IVAL(pdata, 4) != SMB_SIZE_NO_CHANGE_HI) {
+ *p_size=IVAL(pdata,0); /* first 8 Bytes are size */
+#ifdef LARGE_SMB_OFF_T
+ *p_size |= (((SMB_OFF_T)IVAL(pdata,4)) << 32);
+#else /* LARGE_SMB_OFF_T */
+ if (IVAL(pdata,4) != 0) {
+ /* more than 32 bits? */
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+#endif /* LARGE_SMB_OFF_T */
+ }
+
+ pdata+=24; /* ctime & st_blocks are not changed */
+ p_tvs->actime = convert_timespec_to_time_t(interpret_long_date(pdata)); /* access_time */
+ p_tvs->modtime = convert_timespec_to_time_t(interpret_long_date(pdata+8)); /* modification_time */
+ pdata+=16;
+ set_owner = (uid_t)IVAL(pdata,0);
+ pdata += 8;
+ set_grp = (gid_t)IVAL(pdata,0);
+ pdata += 8;
+ raw_unixmode = IVAL(pdata,28);
+ *p_unixmode = unix_perms_from_wire(conn, psbuf, raw_unixmode);
+ *p_dosmode = 0; /* Ensure dos mode change doesn't override this. */
+
+ DEBUG(10,("smb_set_file_unix_basic: SMB_SET_FILE_UNIX_BASIC: name = %s \
+size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
+ fname, (double)*p_size, (unsigned int)set_owner, (unsigned int)set_grp, (int)raw_unixmode));
+
+ if (!VALID_STAT(*psbuf)) {
+
+ /*
+ * The only valid use of this is to create character and block
+ * devices, and named pipes. This is deprecated (IMHO) and
+ * a new info level should be used for mknod. JRA.
+ */
+
+ uint32 file_type = IVAL(pdata,0);
+#if defined(HAVE_MAKEDEV)
+ uint32 dev_major = IVAL(pdata,4);
+ uint32 dev_minor = IVAL(pdata,12);
+#endif
+
+ SMB_DEV_T dev = (SMB_DEV_T)0;
+
+ if (raw_unixmode == SMB_MODE_NO_CHANGE) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+#if defined(HAVE_MAKEDEV)
+ dev = makedev(dev_major, dev_minor);
+#endif
+
+ switch (file_type) {
+#if defined(S_IFIFO)
+ case UNIX_TYPE_FIFO:
+ *p_unixmode |= S_IFIFO;
+ break;
+#endif
+#if defined(S_IFSOCK)
+ case UNIX_TYPE_SOCKET:
+ *p_unixmode |= S_IFSOCK;
+ break;
+#endif
+#if defined(S_IFCHR)
+ case UNIX_TYPE_CHARDEV:
+ *p_unixmode |= S_IFCHR;
+ break;
+#endif
+#if defined(S_IFBLK)
+ case UNIX_TYPE_BLKDEV:
+ *p_unixmode |= S_IFBLK;
+ break;
+#endif
+ default:
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ DEBUG(10,("smb_set_file_unix_basic: SMB_SET_FILE_UNIX_BASIC doing mknod dev %.0f mode \
+0%o for file %s\n", (double)dev, *p_unixmode, fname ));
+
+ /* Ok - do the mknod. */
+ if (SMB_VFS_MKNOD(conn, fname, *p_unixmode, dev) != 0) {
+ return map_nt_error_from_unix(errno);
+ }
+
+ /* If any of the other "set" calls fail we
+ * don't want to end up with a half-constructed mknod.
+ */
+
+ delete_on_fail = True;
+
+ if (lp_inherit_perms(SNUM(conn))) {
+ inherit_access_acl(
+ conn, parent_dirname(fname),
+ fname, *p_unixmode);
+ }
+
+ if (SMB_VFS_STAT(conn, fname, psbuf) != 0) {
+ status = map_nt_error_from_unix(errno);
+ SMB_VFS_UNLINK(conn,fname);
+ return status;
+ }
+
+ /* Ensure we don't try and change anything else. */
+ raw_unixmode = SMB_MODE_NO_CHANGE;
+ *p_size = get_file_size(*psbuf);
+ p_tvs->modtime = psbuf->st_mtime;
+ p_tvs->actime = psbuf->st_atime;
+ }
+
+ /*
+ * Deal with the UNIX specific mode set.
+ */
+
+ if (raw_unixmode != SMB_MODE_NO_CHANGE) {
+ DEBUG(10,("smb_set_file_unix_basic: SMB_SET_FILE_UNIX_BASIC setting mode 0%o for file %s\n",
+ (unsigned int)*p_unixmode, fname ));
+ if (SMB_VFS_CHMOD(conn,fname,*p_unixmode) != 0) {
+ return map_nt_error_from_unix(errno);
+ }
+ }
+
+ /*
+ * Deal with the UNIX specific uid set.
+ */
+
+ if ((set_owner != (uid_t)SMB_UID_NO_CHANGE) && (psbuf->st_uid != set_owner)) {
+ DEBUG(10,("smb_set_file_unix_basic: SMB_SET_FILE_UNIX_BASIC changing owner %u for file %s\n",
+ (unsigned int)set_owner, fname ));
+ if (SMB_VFS_CHOWN(conn, fname, set_owner, (gid_t)-1) != 0) {
+ status = map_nt_error_from_unix(errno);
+ if (delete_on_fail) {
+ SMB_VFS_UNLINK(conn,fname);
+ }
+ return status;
+ }
+ }
+
+ /*
+ * Deal with the UNIX specific gid set.
+ */
+
+ if ((set_grp != (uid_t)SMB_GID_NO_CHANGE) && (psbuf->st_gid != set_grp)) {
+ DEBUG(10,("smb_set_file_unix_basic: SMB_SET_FILE_UNIX_BASIC changing group %u for file %s\n",
+ (unsigned int)set_owner, fname ));
+ if (SMB_VFS_CHOWN(conn, fname, (uid_t)-1, set_grp) != 0) {
+ status = map_nt_error_from_unix(errno);
+ if (delete_on_fail) {
+ SMB_VFS_UNLINK(conn,fname);
+ }
+ return status;
+ }
+ }
+ return NT_STATUS_OK;
+}
/****************************************************************************
Reply to a TRANS2_SETFILEINFO (set file info by fileid or pathname).
@@ -4395,8 +4591,6 @@ static int call_trans2setfilepathinfo(connection_struct *conn, char *inbuf, char
pstring fname;
int fd = -1;
files_struct *fsp = NULL;
- uid_t set_owner = (uid_t)SMB_UID_NO_CHANGE;
- gid_t set_grp = (uid_t)SMB_GID_NO_CHANGE;
mode_t unixmode = 0;
NTSTATUS status = NT_STATUS_OK;
@@ -4520,9 +4714,6 @@ static int call_trans2setfilepathinfo(connection_struct *conn, char *inbuf, char
dosmode = dos_mode(conn,fname,&sbuf);
unixmode = sbuf.st_mode;
- set_owner = VALID_STAT(sbuf) ? sbuf.st_uid : (uid_t)SMB_UID_NO_CHANGE;
- set_grp = VALID_STAT(sbuf) ? sbuf.st_gid : (gid_t)SMB_GID_NO_CHANGE;
-
switch (info_level) {
case SMB_INFO_STANDARD:
@@ -4654,170 +4845,22 @@ static int call_trans2setfilepathinfo(connection_struct *conn, char *inbuf, char
case SMB_SET_FILE_UNIX_BASIC:
{
- uint32 raw_unixmode;
- BOOL delete_on_fail = False;
-
- if (total_data < 100) {
- return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
- }
-
- if(IVAL(pdata, 0) != SMB_SIZE_NO_CHANGE_LO &&
- IVAL(pdata, 4) != SMB_SIZE_NO_CHANGE_HI) {
- size=IVAL(pdata,0); /* first 8 Bytes are size */
-#ifdef LARGE_SMB_OFF_T
- size |= (((SMB_OFF_T)IVAL(pdata,4)) << 32);
-#else /* LARGE_SMB_OFF_T */
- if (IVAL(pdata,4) != 0) {
- /* more than 32 bits? */
- return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
- }
-#endif /* LARGE_SMB_OFF_T */
- }
- pdata+=24; /* ctime & st_blocks are not changed */
- tvs.actime = convert_timespec_to_time_t(interpret_long_date(pdata)); /* access_time */
- tvs.modtime = convert_timespec_to_time_t(interpret_long_date(pdata+8)); /* modification_time */
- pdata+=16;
- set_owner = (uid_t)IVAL(pdata,0);
- pdata += 8;
- set_grp = (gid_t)IVAL(pdata,0);
- pdata += 8;
- raw_unixmode = IVAL(pdata,28);
- unixmode = unix_perms_from_wire(conn, &sbuf, raw_unixmode);
- dosmode = 0; /* Ensure dos mode change doesn't override this. */
-
- DEBUG(10,("call_trans2setfilepathinfo: SMB_SET_FILE_UNIX_BASIC: name = %s \
-size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
- fname, (double)size, (unsigned int)set_owner, (unsigned int)set_grp, (int)raw_unixmode));
-
- if (!VALID_STAT(sbuf)) {
-
- /*
- * The only valid use of this is to create character and block
- * devices, and named pipes. This is deprecated (IMHO) and
- * a new info level should be used for mknod. JRA.
- */
-
- uint32 file_type = IVAL(pdata,0);
-#if defined(HAVE_MAKEDEV)
- uint32 dev_major = IVAL(pdata,4);
- uint32 dev_minor = IVAL(pdata,12);
-#endif
-
- SMB_DEV_T dev = (SMB_DEV_T)0;
-
- if (tran_call == TRANSACT2_SETFILEINFO)
- return(ERROR_DOS(ERRDOS,ERRnoaccess));
-
- if (raw_unixmode == SMB_MODE_NO_CHANGE) {
- return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
- }
-
-#if defined(HAVE_MAKEDEV)
- dev = makedev(dev_major, dev_minor);
-#endif
-
- switch (file_type) {
-#if defined(S_IFIFO)
- case UNIX_TYPE_FIFO:
- unixmode |= S_IFIFO;
- break;
-#endif
-#if defined(S_IFSOCK)
- case UNIX_TYPE_SOCKET:
- unixmode |= S_IFSOCK;
- break;
-#endif
-#if defined(S_IFCHR)
- case UNIX_TYPE_CHARDEV:
- unixmode |= S_IFCHR;
- break;
-#endif
-#if defined(S_IFBLK)
- case UNIX_TYPE_BLKDEV:
- unixmode |= S_IFBLK;
- break;
-#endif
- default:
- return(ERROR_DOS(ERRDOS,ERRnoaccess));
- }
-
- DEBUG(10,("call_trans2setfilepathinfo: SMB_SET_FILE_UNIX_BASIC doing mknod dev %.0f mode \
-0%o for file %s\n", (double)dev, unixmode, fname ));
-
- /* Ok - do the mknod. */
- if (SMB_VFS_MKNOD(conn,fname, unixmode, dev) != 0) {
- return(UNIXERROR(ERRDOS,ERRnoaccess));
- }
-
- /* If any of the other "set" calls fail we
- * don't want to end up with a half-constructed mknod.
- */
-
- delete_on_fail = True;
-
- if (lp_inherit_perms(SNUM(conn))) {
- inherit_access_acl(
- conn, parent_dirname(fname),
- fname, unixmode);
- }
-
- if (SMB_VFS_STAT(conn, fname, &sbuf) != 0) {
- int saved_errno = errno;
- SMB_VFS_UNLINK(conn,fname);
- errno = saved_errno;
- return(UNIXERROR(ERRDOS,ERRnoaccess));
- }
-
- /* Ensure we don't try and change anything else. */
- raw_unixmode = SMB_MODE_NO_CHANGE;
- size = get_file_size(sbuf);
- tvs.modtime = sbuf.st_mtime;
- tvs.actime = sbuf.st_atime;
- }
-
- /*
- * Deal with the UNIX specific mode set.
- */
-
- if (raw_unixmode != SMB_MODE_NO_CHANGE) {
- DEBUG(10,("call_trans2setfilepathinfo: SMB_SET_FILE_UNIX_BASIC setting mode 0%o for file %s\n",
- (unsigned int)unixmode, fname ));
- if (SMB_VFS_CHMOD(conn,fname,unixmode) != 0)
- return(UNIXERROR(ERRDOS,ERRnoaccess));
- }
-
- /*
- * Deal with the UNIX specific uid set.
- */
-
- if ((set_owner != (uid_t)SMB_UID_NO_CHANGE) && (sbuf.st_uid != set_owner)) {
- DEBUG(10,("call_trans2setfilepathinfo: SMB_SET_FILE_UNIX_BASIC changing owner %u for file %s\n",
- (unsigned int)set_owner, fname ));
- if (SMB_VFS_CHOWN(conn,fname,set_owner, (gid_t)-1) != 0) {
- if (delete_on_fail) {
- int saved_errno = errno;
- SMB_VFS_UNLINK(conn,fname);
- errno = saved_errno;
- }
- return(UNIXERROR(ERRDOS,ERRnoaccess));
- }
+ if (tran_call == TRANSACT2_SETFILEINFO) {
+ return ERROR_NT(NT_STATUS_INVALID_LEVEL);
}
- /*
- * Deal with the UNIX specific gid set.
- */
-
- if ((set_grp != (uid_t)SMB_GID_NO_CHANGE) && (sbuf.st_gid != set_grp)) {
- DEBUG(10,("call_trans2setfilepathinfo: SMB_SET_FILE_UNIX_BASIC changing group %u for file %s\n",
- (unsigned int)set_owner, fname ));
- if (SMB_VFS_CHOWN(conn,fname,(uid_t)-1, set_grp) != 0) {
- if (delete_on_fail) {
- int saved_errno = errno;
- SMB_VFS_UNLINK(conn,fname);
- errno = saved_errno;
- }
- return(UNIXERROR(ERRDOS,ERRnoaccess));
- }
+ status = smb_set_file_unix_basic(conn,
+ pdata,
+ total_data,
+ fsp,
+ fname,
+ &sbuf,
+ &size,
+ &tvs,
+ &unixmode,
+ &dosmode);
+ if (!NT_STATUS_IS_OK(status)) {
+ return ERROR_NT(status);
}
break;
}
diff --git a/source3/smbd/vfs.c b/source3/smbd/vfs.c
index 47ac9ef461..643c48cd27 100644
--- a/source3/smbd/vfs.c
+++ b/source3/smbd/vfs.c
@@ -454,6 +454,7 @@ int vfs_allocate_file_space(files_struct *fsp, SMB_BIG_UINT len)
if (((SMB_OFF_T)len) < 0) {
DEBUG(0,("vfs_allocate_file_space: %s negative len requested.\n", fsp->fsp_name ));
+ errno = EINVAL;
return -1;
}