diff options
-rw-r--r-- | source3/include/proto.h | 7 | ||||
-rw-r--r-- | source3/smbd/nttrans.c | 131 | ||||
-rw-r--r-- | source3/smbd/smb2_getinfo.c | 82 |
3 files changed, 174 insertions, 46 deletions
diff --git a/source3/include/proto.h b/source3/include/proto.h index a27ef89d01..ff4a04b4fa 100644 --- a/source3/include/proto.h +++ b/source3/include/proto.h @@ -6616,6 +6616,13 @@ void reply_ntcreate_and_X(struct smb_request *req); struct ea_list *read_nttrans_ea_list(TALLOC_CTX *ctx, const char *pdata, size_t data_size); void reply_ntcancel(struct smb_request *req); void reply_ntrename(struct smb_request *req); +NTSTATUS smbd_do_query_security_desc(connection_struct *conn, + TALLOC_CTX *mem_ctx, + files_struct *fsp, + uint32_t security_info_wanted, + uint32_t max_data_count, + uint8_t **ppmarshalled_sd, + size_t *psd_size); void reply_nttrans(struct smb_request *req); void reply_nttranss(struct smb_request *req); diff --git a/source3/smbd/nttrans.c b/source3/smbd/nttrans.c index 2783545540..3ce196d467 100644 --- a/source3/smbd/nttrans.c +++ b/source3/smbd/nttrans.c @@ -1770,6 +1770,75 @@ static NTSTATUS get_null_nt_acl(TALLOC_CTX *mem_ctx, SEC_DESC **ppsd) /**************************************************************************** Reply to query a security descriptor. + Callable from SMB2 and SMB2. + If it returns NT_STATUS_BUFFER_TOO_SMALL, pdata_size is initialized with + the required size. +****************************************************************************/ + +NTSTATUS smbd_do_query_security_desc(connection_struct *conn, + TALLOC_CTX *mem_ctx, + files_struct *fsp, + uint32_t security_info_wanted, + uint32_t max_data_count, + uint8_t **ppmarshalled_sd, + size_t *psd_size) +{ + NTSTATUS status; + SEC_DESC *psd = NULL; + + /* + * Get the permissions to return. + */ + + if (!lp_nt_acl_support(SNUM(conn))) { + status = get_null_nt_acl(mem_ctx, &psd); + } else { + status = SMB_VFS_FGET_NT_ACL( + fsp, security_info_wanted, &psd); + } + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + /* If the SACL/DACL is NULL, but was requested, we mark that it is + * present in the reply to match Windows behavior */ + if (psd->sacl == NULL && + security_info_wanted & SACL_SECURITY_INFORMATION) + psd->type |= SEC_DESC_SACL_PRESENT; + if (psd->dacl == NULL && + security_info_wanted & DACL_SECURITY_INFORMATION) + psd->type |= SEC_DESC_DACL_PRESENT; + + *psd_size = ndr_size_security_descriptor(psd, NULL, 0); + + DEBUG(3,("smbd_do_query_security_desc: sd_size = %lu.\n", + (unsigned long)*psd_size)); + + if (DEBUGLEVEL >= 10) { + DEBUG(10,("smbd_do_query_security_desc for file %s\n", + fsp_str_dbg(fsp))); + NDR_PRINT_DEBUG(security_descriptor, psd); + } + + if (max_data_count < *psd_size) { + TALLOC_FREE(psd); + return NT_STATUS_BUFFER_TOO_SMALL; + } + + status = marshall_sec_desc(mem_ctx, psd, + ppmarshalled_sd, psd_size); + + if (!NT_STATUS_IS_OK(status)) { + TALLOC_FREE(psd); + return status; + } + + TALLOC_FREE(psd); + return NT_STATUS_OK; +} + +/**************************************************************************** + SMB1 reply to query a security descriptor. ****************************************************************************/ static void call_nt_transact_query_security_desc(connection_struct *conn, @@ -1784,12 +1853,11 @@ static void call_nt_transact_query_security_desc(connection_struct *conn, { char *params = *ppparams; char *data = *ppdata; - SEC_DESC *psd = NULL; - size_t sd_size; + size_t sd_size = 0; uint32 security_info_wanted; files_struct *fsp = NULL; NTSTATUS status; - DATA_BLOB blob; + uint8_t *marshalled_sd = NULL; if(parameter_count < 8) { reply_nterror(req, NT_STATUS_INVALID_PARAMETER); @@ -1818,46 +1886,38 @@ static void call_nt_transact_query_security_desc(connection_struct *conn, * Get the permissions to return. */ - if (!lp_nt_acl_support(SNUM(conn))) { - status = get_null_nt_acl(talloc_tos(), &psd); - } else { - status = SMB_VFS_FGET_NT_ACL( - fsp, security_info_wanted, &psd); - } + status = smbd_do_query_security_desc(conn, + talloc_tos(), + fsp, + security_info_wanted, + max_data_count, + &marshalled_sd, + &sd_size); + + if (NT_STATUS_EQUAL(status, NT_STATUS_BUFFER_TOO_SMALL)) { + SIVAL(params,0,(uint32_t)sd_size); + send_nt_replies(conn, req, NT_STATUS_BUFFER_TOO_SMALL, + params, 4, NULL, 0); + return; + } + if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); return; } - /* If the SACL/DACL is NULL, but was requested, we mark that it is - * present in the reply to match Windows behavior */ - if (psd->sacl == NULL && - security_info_wanted & SACL_SECURITY_INFORMATION) - psd->type |= SEC_DESC_SACL_PRESENT; - if (psd->dacl == NULL && - security_info_wanted & DACL_SECURITY_INFORMATION) - psd->type |= SEC_DESC_DACL_PRESENT; - - sd_size = ndr_size_security_descriptor(psd, NULL, 0); - - 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_str_dbg(fsp))); - NDR_PRINT_DEBUG(security_descriptor, psd); - } + SMB_ASSERT(sd_size > 0); - SIVAL(params,0,(uint32)sd_size); + SIVAL(params,0,(uint32_t)sd_size); if (max_data_count < sd_size) { send_nt_replies(conn, req, NT_STATUS_BUFFER_TOO_SMALL, - params, 4, *ppdata, 0); + params, 4, NULL, 0); return; } /* - * Allocate the data we will point this at. + * Allocate the data we will return. */ data = nttrans_realloc(ppdata, sd_size); @@ -1866,16 +1926,7 @@ static void call_nt_transact_query_security_desc(connection_struct *conn, return; } - status = marshall_sec_desc(talloc_tos(), psd, - &blob.data, &blob.length); - - if (!NT_STATUS_IS_OK(status)) { - reply_nterror(req, status); - return; - } - - SMB_ASSERT(sd_size == blob.length); - memcpy(data, blob.data, sd_size); + memcpy(data, marshalled_sd, sd_size); send_nt_replies(conn, req, NT_STATUS_OK, params, 4, data, (int)sd_size); diff --git a/source3/smbd/smb2_getinfo.c b/source3/smbd/smb2_getinfo.c index 3a8c07757e..d59339fa59 100644 --- a/source3/smbd/smb2_getinfo.c +++ b/source3/smbd/smb2_getinfo.c @@ -34,7 +34,8 @@ static struct tevent_req *smbd_smb2_getinfo_send(TALLOC_CTX *mem_ctx, uint64_t in_file_id_volatile); static NTSTATUS smbd_smb2_getinfo_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, - DATA_BLOB *out_output_buffer); + DATA_BLOB *out_output_buffer, + NTSTATUS *p_call_status); static void smbd_smb2_request_getinfo_done(struct tevent_req *subreq); NTSTATUS smbd_smb2_request_process_getinfo(struct smbd_smb2_request *req) @@ -128,11 +129,13 @@ static void smbd_smb2_request_getinfo_done(struct tevent_req *subreq) uint16_t out_output_buffer_offset; DATA_BLOB out_output_buffer = data_blob_null; NTSTATUS status; + NTSTATUS call_status; NTSTATUS error; /* transport error */ status = smbd_smb2_getinfo_recv(subreq, req, - &out_output_buffer); + &out_output_buffer, + &call_status); TALLOC_FREE(subreq); if (!NT_STATUS_IS_OK(status)) { error = smbd_smb2_request_error(req, status); @@ -144,6 +147,20 @@ static void smbd_smb2_request_getinfo_done(struct tevent_req *subreq) return; } + if (!NT_STATUS_IS_OK(call_status)) { + /* Return a specific error with data. */ + error = smbd_smb2_request_error_ex(req, + call_status, + &out_output_buffer, + __location__); + if (!NT_STATUS_IS_OK(error)) { + smbd_server_connection_terminate(req->sconn, + nt_errstr(error)); + return; + } + return; + } + out_output_buffer_offset = SMB2_HDR_BODY + 0x08; outhdr = (uint8_t *)req->out.vector[i].iov_base; @@ -197,6 +214,7 @@ static struct tevent_req *smbd_smb2_getinfo_send(TALLOC_CTX *mem_ctx, struct smb_request *smbreq; connection_struct *conn = smb2req->tcon->compat_conn; files_struct *fsp; + NTSTATUS status; req = tevent_req_create(mem_ctx, &state, struct smbd_smb2_getinfo_state); @@ -204,7 +222,7 @@ static struct tevent_req *smbd_smb2_getinfo_send(TALLOC_CTX *mem_ctx, return NULL; } state->smb2req = smb2req; - state->status = NT_STATUS_INTERNAL_ERROR; + state->status = NT_STATUS_OK; state->out_output_buffer = data_blob_null; DEBUG(10,("smbd_smb2_getinfo_send: file_id[0x%016llX]\n", @@ -246,7 +264,6 @@ static struct tevent_req *smbd_smb2_getinfo_send(TALLOC_CTX *mem_ctx, struct ea_list *ea_list = NULL; int lock_data_count = 0; char *lock_data = NULL; - NTSTATUS status; ZERO_STRUCT(write_time_ts); @@ -360,7 +377,6 @@ static struct tevent_req *smbd_smb2_getinfo_send(TALLOC_CTX *mem_ctx, 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; @@ -392,7 +408,59 @@ static struct tevent_req *smbd_smb2_getinfo_send(TALLOC_CTX *mem_ctx, break; } + case 0x03:/* SMB2_GETINFO_SEC */ + { + uint8_t *p_marshalled_sd = NULL; + size_t sd_size = 0; + + status = smbd_do_query_security_desc(conn, + state, + fsp, + /* Security info wanted. */ + in_additional_information, + in_output_buffer_length, + &p_marshalled_sd, + &sd_size); + + if (NT_STATUS_EQUAL(status, NT_STATUS_BUFFER_TOO_SMALL)) { + /* Return needed size. */ + state->out_output_buffer = data_blob_talloc(state, + NULL, + 4); + if (tevent_req_nomem(state->out_output_buffer.data, req)) { + return tevent_req_post(req, ev); + } + SIVAL(state->out_output_buffer.data,0,(uint32_t)sd_size); + state->status = NT_STATUS_BUFFER_TOO_SMALL; + break; + } + if (!NT_STATUS_IS_OK(status)) { + DEBUG(10,("smbd_smb2_getinfo_send: " + "smbd_do_query_security_desc of %s failed " + "(%s)\n", fsp_str_dbg(fsp), + nt_errstr(status))); + tevent_req_nterror(req, status); + return tevent_req_post(req, ev); + } + + if (sd_size > 0) { + state->out_output_buffer = data_blob_talloc(state, + p_marshalled_sd, + sd_size); + if (tevent_req_nomem(state->out_output_buffer.data, req)) { + return tevent_req_post(req, ev); + } + } + break; + } + default: + DEBUG(10,("smbd_smb2_getinfo_send: " + "unknown in_info_type of %u " + " for file %s\n", + (unsigned int)in_info_type, + fsp_str_dbg(fsp) )); + tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); return tevent_req_post(req, ev); } @@ -403,7 +471,8 @@ static struct tevent_req *smbd_smb2_getinfo_send(TALLOC_CTX *mem_ctx, static NTSTATUS smbd_smb2_getinfo_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, - DATA_BLOB *out_output_buffer) + DATA_BLOB *out_output_buffer, + NTSTATUS *pstatus) { NTSTATUS status; struct smbd_smb2_getinfo_state *state = tevent_req_data(req, @@ -416,6 +485,7 @@ static NTSTATUS smbd_smb2_getinfo_recv(struct tevent_req *req, *out_output_buffer = state->out_output_buffer; talloc_steal(mem_ctx, out_output_buffer->data); + *pstatus = state->status; tevent_req_received(req); return NT_STATUS_OK; |