From 23cab30c72b1fb91ef9f05dcc882a2f7db8b7749 Mon Sep 17 00:00:00 2001 From: Partha Sarathi Date: Thu, 14 Apr 2016 12:39:05 +0000 Subject: [PATCH] Fix the smb2_setinfo to handle FS info types and FSQUOTA infolevel BUG: https://bugzilla.samba.org/show_bug.cgi?id=11819 Signed-off-by: Partha Sarathi Reviewed-by: Jeremy Allison Reviewed-by: Uri Simchoni Autobuild-User(master): Uri Simchoni Autobuild-Date(master): Wed Apr 27 05:39:01 CEST 2016 on sn-devel-144 (cherry picked from commit 07e2f4731e5819a893c4675d93fede5ea261bed7) --- source3/smbd/globals.h | 7 +++ source3/smbd/smb2_setinfo.c | 18 ++++++ source3/smbd/trans2.c | 143 ++++++++++++++++++++++++++++---------------- 3 files changed, 116 insertions(+), 52 deletions(-) diff --git a/source3/smbd/globals.h b/source3/smbd/globals.h index c843f5a..15f29a8 100644 --- a/source3/smbd/globals.h +++ b/source3/smbd/globals.h @@ -140,6 +140,13 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn, char **ppdata, unsigned int *pdata_size); +NTSTATUS smbd_do_setfsinfo(connection_struct *conn, + struct smb_request *req, + TALLOC_CTX *mem_ctx, + uint16_t info_level, + files_struct *fsp, + const DATA_BLOB *pdata); + NTSTATUS smbd_do_setfilepathinfo(connection_struct *conn, struct smb_request *req, TALLOC_CTX *mem_ctx, diff --git a/source3/smbd/smb2_setinfo.c b/source3/smbd/smb2_setinfo.c index 9361aea..a9196fe 100644 --- a/source3/smbd/smb2_setinfo.c +++ b/source3/smbd/smb2_setinfo.c @@ -530,6 +530,24 @@ static struct tevent_req *smbd_smb2_setinfo_send(TALLOC_CTX *mem_ctx, break; } + case 0x02:/* SMB2_SETINFO_FS */ + { + uint16_t file_info_level = in_file_info_class + 1000; + + status = smbd_do_setfsinfo(conn, smbreq, state, + file_info_level, + fsp, + &in_input_buffer); + 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; + } + case 0x03:/* SMB2_SETINFO_SECURITY */ { if (!CAN_WRITE(conn)) { diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c index b65f581..1780d6f 100644 --- a/source3/smbd/trans2.c +++ b/source3/smbd/trans2.c @@ -3930,6 +3930,86 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned return status; } +static NTSTATUS smb_set_fsquota(connection_struct *conn, + struct smb_request *req, + files_struct *fsp, + const DATA_BLOB *qdata) +{ + NTSTATUS status; + SMB_NTQUOTA_STRUCT quotas; + + ZERO_STRUCT(quotas); + + /* access check */ + if ((get_current_uid(conn) != 0) || !CAN_WRITE(conn)) { + DEBUG(3, ("set_fsquota: access_denied service [%s] user [%s]\n", + lp_servicename(talloc_tos(), SNUM(conn)), + conn->session_info->unix_info->unix_name)); + return NT_STATUS_ACCESS_DENIED; + } + + if (!check_fsp_ntquota_handle(conn, req, + fsp)) { + DEBUG(1, ("set_fsquota: no valid QUOTA HANDLE\n")); + return NT_STATUS_INVALID_HANDLE; + } + + /* note: normally there're 48 bytes, + * but we didn't use the last 6 bytes for now + * --metze + */ + if (qdata->length < 42) { + DEBUG(0,("set_fsquota: requires total_data(%u) >= 42 bytes!\n", + (unsigned int)qdata->length)); + return NT_STATUS_INVALID_PARAMETER; + } + + /* unknown_1 24 NULL bytes in pdata*/ + + /* the soft quotas 8 bytes (uint64_t)*/ + quotas.softlim = BVAL(qdata->data,24); + + /* the hard quotas 8 bytes (uint64_t)*/ + quotas.hardlim = BVAL(qdata->data,32); + + /* quota_flags 2 bytes **/ + quotas.qflags = SVAL(qdata->data,40); + + /* unknown_2 6 NULL bytes follow*/ + + /* now set the quotas */ + if (vfs_set_ntquota(fsp, SMB_USER_FS_QUOTA_TYPE, NULL, "as)!=0) { + DEBUG(1, ("vfs_set_ntquota() failed for service [%s]\n", + lp_servicename(talloc_tos(), SNUM(conn)))); + status = map_nt_error_from_unix(errno); + } else { + status = NT_STATUS_OK; + } + return status; +} + +NTSTATUS smbd_do_setfsinfo(connection_struct *conn, + struct smb_request *req, + TALLOC_CTX *mem_ctx, + uint16_t info_level, + files_struct *fsp, + const DATA_BLOB *pdata) +{ + switch (info_level) { + case SMB_FS_QUOTA_INFORMATION: + { + return smb_set_fsquota(conn, + req, + fsp, + pdata); + } + + default: + break; + } + return NT_STATUS_INVALID_LEVEL; +} + /**************************************************************************** Reply to a TRANS2_QFSINFO (query filesystem info). ****************************************************************************/ @@ -4157,63 +4237,22 @@ static void call_trans2setfsinfo(connection_struct *conn, case SMB_FS_QUOTA_INFORMATION: { + NTSTATUS status; + DATA_BLOB qdata = { + .data = (uint8_t *)pdata, + .length = total_data + }; files_struct *fsp = NULL; - SMB_NTQUOTA_STRUCT quotas; - - ZERO_STRUCT(quotas); - - /* access check */ - if ((get_current_uid(conn) != 0) || !CAN_WRITE(conn)) { - DEBUG(0,("set_user_quota: access_denied service [%s] user [%s]\n", - lp_servicename(talloc_tos(), SNUM(conn)), - conn->session_info->unix_info->unix_name)); - reply_nterror(req, NT_STATUS_ACCESS_DENIED); - return; - } - - /* note: normally there're 48 bytes, - * but we didn't use the last 6 bytes for now - * --metze - */ fsp = file_fsp(req, SVAL(params,0)); - if (!check_fsp_ntquota_handle(conn, req, - fsp)) { - DEBUG(3,("TRANSACT_GET_USER_QUOTA: no valid QUOTA HANDLE\n")); - reply_nterror( - req, NT_STATUS_INVALID_HANDLE); - return; - } - - if (total_data < 42) { - DEBUG(0,("call_trans2setfsinfo: SET_FS_QUOTA: requires total_data(%d) >= 42 bytes!\n", - total_data)); - reply_nterror( - req, - NT_STATUS_INVALID_PARAMETER); - return; - } - - /* unknown_1 24 NULL bytes in pdata*/ - - /* the soft quotas 8 bytes (uint64_t)*/ - quotas.softlim = BVAL(pdata,24); - - /* the hard quotas 8 bytes (uint64_t)*/ - quotas.hardlim = BVAL(pdata,32); - - /* quota_flags 2 bytes **/ - quotas.qflags = SVAL(pdata,40); - - /* unknown_2 6 NULL bytes follow*/ - - /* 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(talloc_tos(), SNUM(conn)))); - reply_nterror(req, map_nt_error_from_unix(errno)); + status = smb_set_fsquota(conn, + req, + fsp, + &qdata); + if (!NT_STATUS_IS_OK(status)) { + reply_nterror(req, status); return; } - break; } default: -- 2.8.0.rc3.226.g39d4020