diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-05 17:47:29 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-05 17:47:29 +0000 |
commit | 4f5791ebd03eaec1c7da0865a383175b05102712 (patch) | |
tree | 8ce7b00f7a76baa386372422adebbe64510812d4 /source3/rpc_server/mdssvc/srv_mdssvc_nt.c | |
parent | Initial commit. (diff) | |
download | samba-upstream.tar.xz samba-upstream.zip |
Adding upstream version 2:4.17.12+dfsg.upstream/2%4.17.12+dfsgupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'source3/rpc_server/mdssvc/srv_mdssvc_nt.c')
-rw-r--r-- | source3/rpc_server/mdssvc/srv_mdssvc_nt.c | 319 |
1 files changed, 319 insertions, 0 deletions
diff --git a/source3/rpc_server/mdssvc/srv_mdssvc_nt.c b/source3/rpc_server/mdssvc/srv_mdssvc_nt.c new file mode 100644 index 0000000..9a16624 --- /dev/null +++ b/source3/rpc_server/mdssvc/srv_mdssvc_nt.c @@ -0,0 +1,319 @@ +/* + * 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" |