mirror of
https://github.com/samba-team/samba.git
synced 2025-01-11 05:18:09 +03:00
044cb8f9d5
Environment setup:
When macOS Finder connect to a samba server with 'spotlight = yes',
macOS would issue mdssvc open (mdssvc.opnum == 0) to samba and it goes
through api _mdssvc_open().
After applied 578e434a94
,
(this is reported by jaywei@qnap.com)
this line 'talloc_free(path);' is deleted if _mdssvc_open() normal exit,
so memory is lazy de-allocate: delayed to
smbd_tevent_trace_callback() @ smb2_process.c. [1]
Supposed to explicitly free 'path' in _mdssvc_open() @ srv_mdssvc_nt.c[2]
just like abnormal exit, do not wait for main loop to free 'path' which is
no longer used, this is more consistent while reading source code.
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15449
[1] gdb tracing 'path' address 0x56204ccc67e0 to know how it is freed.
Breakpoint 2, _tc_free_children_internal (tc=0x56204ccc6780, ptr=0x56204ccc67e0, location=0x7ff430d96410 "../../lib/talloc/talloc.c:1714") at ../../lib/talloc/talloc.c:1656
1656 while (tc->child) {
(gdb) bt
0 _tc_free_children_internal (tc=0x56204ccc6780, ptr=0x56204ccc67e0, location=0x7ff430d96410 "../../lib/talloc/talloc.c:1714") at ../../lib/talloc/talloc.c:1656
1 0x00007ff430d92b14 in _tc_free_internal (tc=0x56204ccc6780, location=0x7ff430d96410 "../../lib/talloc/talloc.c:1714") at ../../lib/talloc/talloc.c:1183
2 0x00007ff430d93b71 in _tc_free_children_internal (tc=0x56204ccc6720, ptr=0x56204ccc6780, location=0x7ff430d96410 "../../lib/talloc/talloc.c:1714") at ../../lib/talloc/talloc.c:1668
3 0x00007ff430d93d66 in talloc_free_children (ptr=0x56204ccc6780) at ../../lib/talloc/talloc.c:1714
4 0x00007ff432235aca in talloc_pop (frame=0x56204ccc6780) at ../../lib/util/talloc_stack.c:125
5 0x00007ff430d92959 in _tc_free_internal (tc=0x56204ccc6720, location=0x7ff431f358d0 "../../source3/smbd/process.c:3726") at ../../lib/talloc/talloc.c:1157
6 0x00007ff430d92cd5 in _talloc_free_internal (ptr=0x56204ccc6780, location=0x7ff431f358d0 "../../source3/smbd/process.c:3726") at ../../lib/talloc/talloc.c:1247
7 0x00007ff430d93f96 in _talloc_free (ptr=0x56204ccc6780, location=0x7ff431f358d0 "../../source3/smbd/process.c:3726") at ../../lib/talloc/talloc.c:1791
8 0x00007ff431d81292 in smbd_tevent_trace_callback (point=TEVENT_TRACE_AFTER_LOOP_ONCE, private_data=0x7ffe46591e30) at ../../source3/smbd/process.c:3726
<...cut...>
[2] gdb tracing 'path' address 0x55a6d66deed0 to know how it is freed.
Breakpoint 2, _tc_free_children_internal (tc=0x55a6d66deed0, ptr=0x55a6d66def30, location=0x7fc4cca84040 "../../source3/rpc_server/mdssvc/srv_mdssvc_nt.c:189") at ../../lib/talloc/talloc.c:1656
1656 while (tc->child) {
(gdb) bt
0 _tc_free_children_internal (tc=0x55a6d66deed0, ptr=0x55a6d66def30, location=0x7fc4cca84040 "../../source3/rpc_server/mdssvc/srv_mdssvc_nt.c:189") at ../../lib/talloc/talloc.c:1656
1 0x00007fc4cb892b14 in _tc_free_internal (tc=0x55a6d66deed0, location=0x7fc4cca84040 "../../source3/rpc_server/mdssvc/srv_mdssvc_nt.c:189") at ../../lib/talloc/talloc.c:1183
2 0x00007fc4cb892cd5 in _talloc_free_internal (ptr=0x55a6d66def30, location=0x7fc4cca84040 "../../source3/rpc_server/mdssvc/srv_mdssvc_nt.c:189") at ../../lib/talloc/talloc.c:1247
3 0x00007fc4cb893f96 in _talloc_free (ptr=0x55a6d66def30, location=0x7fc4cca84040 "../../source3/rpc_server/mdssvc/srv_mdssvc_nt.c:189") at ../../lib/talloc/talloc.c:1791
4 0x00007fc4cc9396e4 in _mdssvc_open (p=0x55a6d66d5600, r=0x55a6d66edc60) at ../../source3/rpc_server/mdssvc/srv_mdssvc_nt.c:189
<...cut...>
Signed-off-by: Jones Syue <jonessyue@qnap.com>
Reviewed-by: Noel Power <npower@samba.org>
Reviewed-by: Volker Lendecke <vl@samba.org>
Autobuild-User(master): Noel Power <npower@samba.org>
Autobuild-Date(master): Mon Aug 14 18:11:37 UTC 2023 on atb-devel-224
320 lines
7.9 KiB
C
320 lines
7.9 KiB
C
/*
|
|
* Unix SMB/CIFS implementation.
|
|
* RPC Pipe client / server routines for mdssvc
|
|
* Copyright (C) Ralph Boehme 2014
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "includes.h"
|
|
#include "messages.h"
|
|
#include "ntdomain.h"
|
|
#include "rpc_server/rpc_server.h"
|
|
#include "rpc_server/rpc_config.h"
|
|
#include "rpc_server/mdssvc/srv_mdssvc_nt.h"
|
|
#include "libcli/security/security_token.h"
|
|
#include "libcli/security/dom_sid.h"
|
|
#include "gen_ndr/auth.h"
|
|
#include "mdssvc.h"
|
|
#include "smbd/globals.h"
|
|
|
|
#include "librpc/rpc/dcesrv_core.h"
|
|
#include "librpc/gen_ndr/ndr_mdssvc.h"
|
|
#include "librpc/gen_ndr/ndr_mdssvc_scompat.h"
|
|
#include "lib/global_contexts.h"
|
|
|
|
#undef DBGC_CLASS
|
|
#define DBGC_CLASS DBGC_RPC_SRV
|
|
|
|
static NTSTATUS create_mdssvc_policy_handle(TALLOC_CTX *mem_ctx,
|
|
struct pipes_struct *p,
|
|
int snum,
|
|
const char *sharename,
|
|
const char *path,
|
|
struct policy_handle *handle)
|
|
{
|
|
struct dcesrv_call_state *dce_call = p->dce_call;
|
|
struct auth_session_info *session_info =
|
|
dcesrv_call_session_info(dce_call);
|
|
struct mds_ctx *mds_ctx;
|
|
NTSTATUS status;
|
|
|
|
ZERO_STRUCTP(handle);
|
|
|
|
status = mds_init_ctx(mem_ctx,
|
|
messaging_tevent_context(p->msg_ctx),
|
|
p->msg_ctx,
|
|
session_info,
|
|
snum,
|
|
sharename,
|
|
path,
|
|
&mds_ctx);
|
|
if (!NT_STATUS_IS_OK(status)) {
|
|
DBG_DEBUG("mds_init_ctx() path [%s] failed: %s\n",
|
|
path, nt_errstr(status));
|
|
return status;
|
|
}
|
|
|
|
if (!create_policy_hnd(p, handle, 0, mds_ctx)) {
|
|
talloc_free(mds_ctx);
|
|
ZERO_STRUCTP(handle);
|
|
return NT_STATUS_NO_MEMORY;
|
|
}
|
|
|
|
return NT_STATUS_OK;
|
|
}
|
|
|
|
void _mdssvc_open(struct pipes_struct *p, struct mdssvc_open *r)
|
|
{
|
|
const struct loadparm_substitution *lp_sub =
|
|
loadparm_s3_global_substitution();
|
|
int snum;
|
|
char *outpath = discard_const_p(char, r->out.share_path);
|
|
char *fake_path = NULL;
|
|
char *path;
|
|
NTSTATUS status;
|
|
|
|
DBG_DEBUG("[%s]\n", r->in.share_name);
|
|
|
|
*r->out.device_id = *r->in.device_id;
|
|
*r->out.unkn2 = *r->in.unkn2;
|
|
*r->out.unkn3 = *r->in.unkn3;
|
|
outpath[0] = '\0';
|
|
|
|
snum = lp_servicenumber(r->in.share_name);
|
|
if (!VALID_SNUM(snum)) {
|
|
return;
|
|
}
|
|
|
|
path = lp_path(talloc_tos(), lp_sub, snum);
|
|
if (path == NULL) {
|
|
DBG_ERR("Couldn't create path for %s\n",
|
|
r->in.share_name);
|
|
p->fault_state = DCERPC_FAULT_CANT_PERFORM;
|
|
return;
|
|
}
|
|
|
|
fake_path = talloc_asprintf(p->mem_ctx, "/%s", r->in.share_name);
|
|
if (fake_path == NULL) {
|
|
DBG_ERR("Couldn't create fake share path for %s\n",
|
|
r->in.share_name);
|
|
talloc_free(path);
|
|
p->fault_state = DCERPC_FAULT_CANT_PERFORM;
|
|
return;
|
|
}
|
|
|
|
status = create_mdssvc_policy_handle(p->mem_ctx, p,
|
|
snum,
|
|
r->in.share_name,
|
|
path,
|
|
r->out.handle);
|
|
if (NT_STATUS_EQUAL(status, NT_STATUS_WRONG_VOLUME)) {
|
|
ZERO_STRUCTP(r->out.handle);
|
|
talloc_free(path);
|
|
talloc_free(fake_path);
|
|
return;
|
|
}
|
|
if (!NT_STATUS_IS_OK(status)) {
|
|
DBG_ERR("Couldn't create policy handle for %s\n",
|
|
r->in.share_name);
|
|
talloc_free(path);
|
|
talloc_free(fake_path);
|
|
p->fault_state = DCERPC_FAULT_CANT_PERFORM;
|
|
return;
|
|
}
|
|
|
|
strlcpy(outpath, fake_path, 1024);
|
|
talloc_free(path);
|
|
talloc_free(fake_path);
|
|
return;
|
|
}
|
|
|
|
void _mdssvc_unknown1(struct pipes_struct *p, struct mdssvc_unknown1 *r)
|
|
{
|
|
struct mds_ctx *mds_ctx;
|
|
NTSTATUS status;
|
|
|
|
mds_ctx = find_policy_by_hnd(p,
|
|
r->in.handle,
|
|
DCESRV_HANDLE_ANY,
|
|
struct mds_ctx,
|
|
&status);
|
|
if (!NT_STATUS_IS_OK(status)) {
|
|
if (ndr_policy_handle_empty(r->in.handle)) {
|
|
p->fault_state = 0;
|
|
} else {
|
|
p->fault_state = DCERPC_NCA_S_PROTO_ERROR;
|
|
}
|
|
*r->out.status = 0;
|
|
*r->out.flags = 0;
|
|
*r->out.unkn7 = 0;
|
|
return;
|
|
}
|
|
|
|
DEBUG(10, ("%s: path: %s\n", __func__, mds_ctx->spath));
|
|
|
|
*r->out.status = 0;
|
|
*r->out.flags = 0x6b000001;
|
|
*r->out.unkn7 = 0;
|
|
|
|
return;
|
|
}
|
|
|
|
void _mdssvc_cmd(struct pipes_struct *p, struct mdssvc_cmd *r)
|
|
{
|
|
struct dcesrv_call_state *dce_call = p->dce_call;
|
|
struct auth_session_info *session_info =
|
|
dcesrv_call_session_info(dce_call);
|
|
bool ok;
|
|
struct mds_ctx *mds_ctx;
|
|
NTSTATUS status;
|
|
|
|
mds_ctx = find_policy_by_hnd(p,
|
|
r->in.handle,
|
|
DCESRV_HANDLE_ANY,
|
|
struct mds_ctx,
|
|
&status);
|
|
if (!NT_STATUS_IS_OK(status)) {
|
|
if (ndr_policy_handle_empty(r->in.handle)) {
|
|
p->fault_state = 0;
|
|
} else {
|
|
p->fault_state = DCERPC_NCA_S_PROTO_ERROR;
|
|
}
|
|
r->out.response_blob->size = 0;
|
|
*r->out.fragment = 0;
|
|
*r->out.unkn9 = 0;
|
|
return;
|
|
}
|
|
|
|
DEBUG(10, ("%s: path: %s\n", __func__, mds_ctx->spath));
|
|
|
|
ok = security_token_is_sid(session_info->security_token,
|
|
&mds_ctx->sid);
|
|
if (!ok) {
|
|
struct dom_sid_buf buf;
|
|
DBG_WARNING("not the same sid: %s\n",
|
|
dom_sid_str_buf(&mds_ctx->sid, &buf));
|
|
p->fault_state = DCERPC_FAULT_ACCESS_DENIED;
|
|
return;
|
|
}
|
|
|
|
if (geteuid() != mds_ctx->uid) {
|
|
DEBUG(0, ("uid mismatch: %d/%d\n", geteuid(), mds_ctx->uid));
|
|
smb_panic("uid mismatch");
|
|
}
|
|
|
|
if (r->in.request_blob.size > MAX_SL_FRAGMENT_SIZE) {
|
|
DEBUG(1, ("%s: request size too large\n", __func__));
|
|
p->fault_state = DCERPC_FAULT_CANT_PERFORM;
|
|
return;
|
|
}
|
|
|
|
if (r->in.request_blob.length > MAX_SL_FRAGMENT_SIZE) {
|
|
DEBUG(1, ("%s: request length too large\n", __func__));
|
|
p->fault_state = DCERPC_FAULT_CANT_PERFORM;
|
|
return;
|
|
}
|
|
|
|
if (r->in.max_fragment_size1 > MAX_SL_FRAGMENT_SIZE) {
|
|
DEBUG(1, ("%s: request fragment size too large: %u\n",
|
|
__func__, (unsigned)r->in.max_fragment_size1));
|
|
p->fault_state = DCERPC_FAULT_CANT_PERFORM;
|
|
return;
|
|
}
|
|
|
|
/* We currently don't use fragmentation at the mdssvc RPC layer */
|
|
*r->out.fragment = 0;
|
|
|
|
ok = mds_dispatch(mds_ctx,
|
|
&r->in.request_blob,
|
|
r->out.response_blob,
|
|
r->in.max_fragment_size1);
|
|
if (ok) {
|
|
*r->out.unkn9 = 0;
|
|
} else {
|
|
/* FIXME: just interpolating from AFP, needs verification */
|
|
*r->out.unkn9 = UINT32_MAX;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
void _mdssvc_close(struct pipes_struct *p, struct mdssvc_close *r)
|
|
{
|
|
struct mds_ctx *mds_ctx;
|
|
NTSTATUS status;
|
|
|
|
mds_ctx = find_policy_by_hnd(p,
|
|
r->in.in_handle,
|
|
DCESRV_HANDLE_ANY,
|
|
struct mds_ctx,
|
|
&status);
|
|
if (!NT_STATUS_IS_OK(status)) {
|
|
DBG_WARNING("invalid handle\n");
|
|
if (ndr_policy_handle_empty(r->in.in_handle)) {
|
|
p->fault_state = 0;
|
|
} else {
|
|
p->fault_state = DCERPC_NCA_S_PROTO_ERROR;
|
|
}
|
|
return;
|
|
}
|
|
|
|
DBG_DEBUG("Close mdssvc handle for path: %s\n", mds_ctx->spath);
|
|
TALLOC_FREE(mds_ctx);
|
|
|
|
*r->out.out_handle = *r->in.in_handle;
|
|
close_policy_hnd(p, r->in.in_handle);
|
|
|
|
*r->out.status = 0;
|
|
|
|
return;
|
|
}
|
|
|
|
static NTSTATUS mdssvc__op_init_server(struct dcesrv_context *dce_ctx,
|
|
const struct dcesrv_endpoint_server *ep_server);
|
|
|
|
static NTSTATUS mdssvc__op_shutdown_server(struct dcesrv_context *dce_ctx,
|
|
const struct dcesrv_endpoint_server *ep_server);
|
|
|
|
#define DCESRV_INTERFACE_MDSSVC_INIT_SERVER \
|
|
mdssvc_init_server
|
|
|
|
#define DCESRV_INTERFACE_MDSSVC_SHUTDOWN_SERVER \
|
|
mdssvc_shutdown_server
|
|
|
|
static NTSTATUS mdssvc_init_server(struct dcesrv_context *dce_ctx,
|
|
const struct dcesrv_endpoint_server *ep_server)
|
|
{
|
|
struct messaging_context *msg_ctx = global_messaging_context();
|
|
bool ok;
|
|
|
|
ok = mds_init(msg_ctx);
|
|
if (!ok) {
|
|
return NT_STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
return mdssvc__op_init_server(dce_ctx, ep_server);
|
|
}
|
|
|
|
static NTSTATUS mdssvc_shutdown_server(struct dcesrv_context *dce_ctx,
|
|
const struct dcesrv_endpoint_server *ep_server)
|
|
{
|
|
mds_shutdown();
|
|
|
|
return mdssvc__op_shutdown_server(dce_ctx, ep_server);
|
|
}
|
|
|
|
/* include the generated boilerplate */
|
|
#include "librpc/gen_ndr/ndr_mdssvc_scompat.c"
|