Line data Source code
1 : /*
2 : * Unix SMB/CIFS implementation.
3 : * RPC Pipe client / server routines for mdssvc
4 : * Copyright (C) Ralph Boehme 2014
5 : *
6 : * This program is free software; you can redistribute it and/or modify
7 : * it under the terms of the GNU General Public License as published by
8 : * the Free Software Foundation; either version 3 of the License, or
9 : * (at your option) any later version.
10 : *
11 : * This program is distributed in the hope that it will be useful,
12 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : * GNU General Public License for more details.
15 : *
16 : * You should have received a copy of the GNU General Public License
17 : * along with this program; if not, see <http://www.gnu.org/licenses/>.
18 : */
19 :
20 : #include "includes.h"
21 : #include "messages.h"
22 : #include "ntdomain.h"
23 : #include "rpc_server/rpc_server.h"
24 : #include "rpc_server/rpc_config.h"
25 : #include "rpc_server/mdssvc/srv_mdssvc_nt.h"
26 : #include "libcli/security/security_token.h"
27 : #include "libcli/security/dom_sid.h"
28 : #include "gen_ndr/auth.h"
29 : #include "mdssvc.h"
30 : #include "smbd/globals.h"
31 :
32 : #include "librpc/rpc/dcesrv_core.h"
33 : #include "librpc/gen_ndr/ndr_mdssvc.h"
34 : #include "librpc/gen_ndr/ndr_mdssvc_scompat.h"
35 : #include "lib/global_contexts.h"
36 :
37 : #undef DBGC_CLASS
38 : #define DBGC_CLASS DBGC_RPC_SRV
39 :
40 14 : static NTSTATUS create_mdssvc_policy_handle(TALLOC_CTX *mem_ctx,
41 : struct pipes_struct *p,
42 : int snum,
43 : const char *sharename,
44 : const char *path,
45 : struct policy_handle *handle)
46 : {
47 14 : struct dcesrv_call_state *dce_call = p->dce_call;
48 : struct auth_session_info *session_info =
49 14 : dcesrv_call_session_info(dce_call);
50 : struct mds_ctx *mds_ctx;
51 : NTSTATUS status;
52 :
53 14 : ZERO_STRUCTP(handle);
54 :
55 14 : status = mds_init_ctx(mem_ctx,
56 : messaging_tevent_context(p->msg_ctx),
57 : p->msg_ctx,
58 : session_info,
59 : snum,
60 : sharename,
61 : path,
62 : &mds_ctx);
63 14 : if (!NT_STATUS_IS_OK(status)) {
64 2 : DBG_DEBUG("mds_init_ctx() path [%s] failed: %s\n",
65 : path, nt_errstr(status));
66 2 : return status;
67 : }
68 :
69 12 : if (!create_policy_hnd(p, handle, 0, mds_ctx)) {
70 0 : talloc_free(mds_ctx);
71 0 : ZERO_STRUCTP(handle);
72 0 : return NT_STATUS_NO_MEMORY;
73 : }
74 :
75 12 : return NT_STATUS_OK;
76 : }
77 :
78 16 : void _mdssvc_open(struct pipes_struct *p, struct mdssvc_open *r)
79 : {
80 : const struct loadparm_substitution *lp_sub =
81 16 : loadparm_s3_global_substitution();
82 : int snum;
83 16 : char *outpath = discard_const_p(char, r->out.share_path);
84 16 : char *fake_path = NULL;
85 : char *path;
86 : NTSTATUS status;
87 :
88 16 : DBG_DEBUG("[%s]\n", r->in.share_name);
89 :
90 16 : *r->out.device_id = *r->in.device_id;
91 16 : *r->out.unkn2 = *r->in.unkn2;
92 16 : *r->out.unkn3 = *r->in.unkn3;
93 16 : outpath[0] = '\0';
94 :
95 16 : snum = lp_servicenumber(r->in.share_name);
96 16 : if (!VALID_SNUM(snum)) {
97 2 : return;
98 : }
99 :
100 14 : path = lp_path(talloc_tos(), lp_sub, snum);
101 14 : if (path == NULL) {
102 0 : DBG_ERR("Couldn't create path for %s\n",
103 : r->in.share_name);
104 0 : p->fault_state = DCERPC_FAULT_CANT_PERFORM;
105 0 : return;
106 : }
107 :
108 14 : fake_path = talloc_asprintf(p->mem_ctx, "/%s", r->in.share_name);
109 14 : if (fake_path == NULL) {
110 0 : DBG_ERR("Couldn't create fake share path for %s\n",
111 : r->in.share_name);
112 0 : talloc_free(path);
113 0 : p->fault_state = DCERPC_FAULT_CANT_PERFORM;
114 0 : return;
115 : }
116 :
117 14 : status = create_mdssvc_policy_handle(p->mem_ctx, p,
118 : snum,
119 : r->in.share_name,
120 : path,
121 : r->out.handle);
122 14 : if (NT_STATUS_EQUAL(status, NT_STATUS_WRONG_VOLUME)) {
123 2 : ZERO_STRUCTP(r->out.handle);
124 2 : talloc_free(path);
125 2 : talloc_free(fake_path);
126 2 : return;
127 : }
128 12 : if (!NT_STATUS_IS_OK(status)) {
129 0 : DBG_ERR("Couldn't create policy handle for %s\n",
130 : r->in.share_name);
131 0 : talloc_free(path);
132 0 : talloc_free(fake_path);
133 0 : p->fault_state = DCERPC_FAULT_CANT_PERFORM;
134 0 : return;
135 : }
136 :
137 12 : strlcpy(outpath, fake_path, 1024);
138 12 : talloc_free(path);
139 12 : talloc_free(fake_path);
140 12 : return;
141 : }
142 :
143 14 : void _mdssvc_unknown1(struct pipes_struct *p, struct mdssvc_unknown1 *r)
144 : {
145 : struct mds_ctx *mds_ctx;
146 : NTSTATUS status;
147 :
148 14 : mds_ctx = find_policy_by_hnd(p,
149 : r->in.handle,
150 : DCESRV_HANDLE_ANY,
151 : struct mds_ctx,
152 : &status);
153 14 : if (!NT_STATUS_IS_OK(status)) {
154 4 : if (ndr_policy_handle_empty(r->in.handle)) {
155 2 : p->fault_state = 0;
156 : } else {
157 2 : p->fault_state = DCERPC_NCA_S_PROTO_ERROR;
158 : }
159 4 : *r->out.status = 0;
160 4 : *r->out.flags = 0;
161 4 : *r->out.unkn7 = 0;
162 4 : return;
163 : }
164 :
165 10 : DEBUG(10, ("%s: path: %s\n", __func__, mds_ctx->spath));
166 :
167 10 : *r->out.status = 0;
168 10 : *r->out.flags = 0x6b000001;
169 10 : *r->out.unkn7 = 0;
170 :
171 10 : return;
172 : }
173 :
174 22 : void _mdssvc_cmd(struct pipes_struct *p, struct mdssvc_cmd *r)
175 : {
176 22 : struct dcesrv_call_state *dce_call = p->dce_call;
177 : struct auth_session_info *session_info =
178 22 : dcesrv_call_session_info(dce_call);
179 : bool ok;
180 : struct mds_ctx *mds_ctx;
181 : NTSTATUS status;
182 :
183 22 : mds_ctx = find_policy_by_hnd(p,
184 : r->in.handle,
185 : DCESRV_HANDLE_ANY,
186 : struct mds_ctx,
187 : &status);
188 22 : if (!NT_STATUS_IS_OK(status)) {
189 2 : if (ndr_policy_handle_empty(r->in.handle)) {
190 0 : p->fault_state = 0;
191 : } else {
192 2 : p->fault_state = DCERPC_NCA_S_PROTO_ERROR;
193 : }
194 2 : r->out.response_blob->size = 0;
195 2 : *r->out.fragment = 0;
196 2 : *r->out.unkn9 = 0;
197 2 : return;
198 : }
199 :
200 20 : DEBUG(10, ("%s: path: %s\n", __func__, mds_ctx->spath));
201 :
202 20 : ok = security_token_is_sid(session_info->security_token,
203 20 : &mds_ctx->sid);
204 20 : if (!ok) {
205 : struct dom_sid_buf buf;
206 0 : DBG_WARNING("not the same sid: %s\n",
207 : dom_sid_str_buf(&mds_ctx->sid, &buf));
208 0 : p->fault_state = DCERPC_FAULT_ACCESS_DENIED;
209 0 : return;
210 : }
211 :
212 20 : if (geteuid() != mds_ctx->uid) {
213 0 : DEBUG(0, ("uid mismatch: %d/%d\n", geteuid(), mds_ctx->uid));
214 0 : smb_panic("uid mismatch");
215 : }
216 :
217 20 : if (r->in.request_blob.size > MAX_SL_FRAGMENT_SIZE) {
218 0 : DEBUG(1, ("%s: request size too large\n", __func__));
219 0 : p->fault_state = DCERPC_FAULT_CANT_PERFORM;
220 0 : return;
221 : }
222 :
223 20 : if (r->in.request_blob.length > MAX_SL_FRAGMENT_SIZE) {
224 0 : DEBUG(1, ("%s: request length too large\n", __func__));
225 0 : p->fault_state = DCERPC_FAULT_CANT_PERFORM;
226 0 : return;
227 : }
228 :
229 20 : if (r->in.max_fragment_size1 > MAX_SL_FRAGMENT_SIZE) {
230 0 : DEBUG(1, ("%s: request fragment size too large: %u\n",
231 : __func__, (unsigned)r->in.max_fragment_size1));
232 0 : p->fault_state = DCERPC_FAULT_CANT_PERFORM;
233 0 : return;
234 : }
235 :
236 : /* We currently don't use fragmentation at the mdssvc RPC layer */
237 20 : *r->out.fragment = 0;
238 :
239 20 : ok = mds_dispatch(mds_ctx,
240 : &r->in.request_blob,
241 : r->out.response_blob,
242 20 : r->in.max_fragment_size1);
243 20 : if (ok) {
244 18 : *r->out.unkn9 = 0;
245 : } else {
246 : /* FIXME: just interpolating from AFP, needs verification */
247 2 : *r->out.unkn9 = UINT32_MAX;
248 : }
249 :
250 20 : return;
251 : }
252 :
253 10 : void _mdssvc_close(struct pipes_struct *p, struct mdssvc_close *r)
254 : {
255 : struct mds_ctx *mds_ctx;
256 : NTSTATUS status;
257 :
258 10 : mds_ctx = find_policy_by_hnd(p,
259 : r->in.in_handle,
260 : DCESRV_HANDLE_ANY,
261 : struct mds_ctx,
262 : &status);
263 10 : if (!NT_STATUS_IS_OK(status)) {
264 4 : DBG_WARNING("invalid handle\n");
265 4 : if (ndr_policy_handle_empty(r->in.in_handle)) {
266 2 : p->fault_state = 0;
267 : } else {
268 2 : p->fault_state = DCERPC_NCA_S_PROTO_ERROR;
269 : }
270 4 : return;
271 : }
272 :
273 6 : DBG_DEBUG("Close mdssvc handle for path: %s\n", mds_ctx->spath);
274 6 : TALLOC_FREE(mds_ctx);
275 :
276 6 : *r->out.out_handle = *r->in.in_handle;
277 6 : close_policy_hnd(p, r->in.in_handle);
278 :
279 6 : *r->out.status = 0;
280 :
281 6 : return;
282 : }
283 :
284 : static NTSTATUS mdssvc__op_init_server(struct dcesrv_context *dce_ctx,
285 : const struct dcesrv_endpoint_server *ep_server);
286 :
287 : static NTSTATUS mdssvc__op_shutdown_server(struct dcesrv_context *dce_ctx,
288 : const struct dcesrv_endpoint_server *ep_server);
289 :
290 : #define DCESRV_INTERFACE_MDSSVC_INIT_SERVER \
291 : mdssvc_init_server
292 :
293 : #define DCESRV_INTERFACE_MDSSVC_SHUTDOWN_SERVER \
294 : mdssvc_shutdown_server
295 :
296 8 : static NTSTATUS mdssvc_init_server(struct dcesrv_context *dce_ctx,
297 : const struct dcesrv_endpoint_server *ep_server)
298 : {
299 8 : struct messaging_context *msg_ctx = global_messaging_context();
300 : bool ok;
301 :
302 8 : ok = mds_init(msg_ctx);
303 8 : if (!ok) {
304 0 : return NT_STATUS_UNSUCCESSFUL;
305 : }
306 :
307 8 : return mdssvc__op_init_server(dce_ctx, ep_server);
308 : }
309 :
310 8 : static NTSTATUS mdssvc_shutdown_server(struct dcesrv_context *dce_ctx,
311 : const struct dcesrv_endpoint_server *ep_server)
312 : {
313 8 : mds_shutdown();
314 :
315 8 : return mdssvc__op_shutdown_server(dce_ctx, ep_server);
316 : }
317 :
318 : /* include the generated boilerplate */
319 : #include "librpc/gen_ndr/ndr_mdssvc_scompat.c"
|