s3:rpc_server: Activate samba-dcerpcd
[samba.git] / source3 / rpc_server / mdssvc / srv_mdssvc_nt.c
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 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         struct mds_ctx *mds_ctx;
48
49         ZERO_STRUCTP(handle);
50
51         mds_ctx = mds_init_ctx(mem_ctx,
52                                messaging_tevent_context(p->msg_ctx),
53                                p->msg_ctx,
54                                p->session_info,
55                                snum,
56                                sharename,
57                                path);
58         if (mds_ctx == NULL) {
59                 DEBUG(1, ("error in mds_init_ctx for: %s\n", path));
60                 return NT_STATUS_UNSUCCESSFUL;
61         }
62
63         if (!create_policy_hnd(p, handle, 0, mds_ctx)) {
64                 talloc_free(mds_ctx);
65                 ZERO_STRUCTP(handle);
66                 return NT_STATUS_NO_MEMORY;
67         }
68
69         return NT_STATUS_OK;
70 }
71
72 void _mdssvc_open(struct pipes_struct *p, struct mdssvc_open *r)
73 {
74         const struct loadparm_substitution *lp_sub =
75                 loadparm_s3_global_substitution();
76         int snum;
77         char *outpath = discard_const_p(char, r->out.share_path);
78         char *path;
79         NTSTATUS status;
80
81         DBG_DEBUG("[%s]\n", r->in.share_name);
82
83         *r->out.device_id = *r->in.device_id;
84         *r->out.unkn2 = *r->in.unkn2;
85         *r->out.unkn3 = *r->in.unkn3;
86         outpath[0] = '\0';
87
88         snum = lp_servicenumber(r->in.share_name);
89         if (!VALID_SNUM(snum)) {
90                 return;
91         }
92
93         path = lp_path(talloc_tos(), lp_sub, snum);
94         if (path == NULL) {
95                 DBG_ERR("Couldn't create policy handle for %s\n",
96                         r->in.share_name);
97                 p->fault_state = DCERPC_FAULT_CANT_PERFORM;
98                 return;
99         }
100
101         status = create_mdssvc_policy_handle(p->mem_ctx, p,
102                                              snum,
103                                              r->in.share_name,
104                                              path,
105                                              r->out.handle);
106         if (!NT_STATUS_IS_OK(status)) {
107                 DBG_ERR("Couldn't create policy handle for %s\n",
108                         r->in.share_name);
109                 talloc_free(path);
110                 p->fault_state = DCERPC_FAULT_CANT_PERFORM;
111                 return;
112         }
113
114         strlcpy(outpath, path, 1024);
115         talloc_free(path);
116         return;
117 }
118
119 void _mdssvc_unknown1(struct pipes_struct *p, struct mdssvc_unknown1 *r)
120 {
121         struct mds_ctx *mds_ctx;
122         NTSTATUS status;
123
124         mds_ctx = find_policy_by_hnd(p,
125                                      r->in.handle,
126                                      DCESRV_HANDLE_ANY,
127                                      struct mds_ctx,
128                                      &status);
129         if (!NT_STATUS_IS_OK(status)) {
130                 if (ndr_policy_handle_empty(r->in.handle)) {
131                         p->fault_state = 0;
132                 } else {
133                         p->fault_state = DCERPC_NCA_S_PROTO_ERROR;
134                 }
135                 *r->out.status = 0;
136                 *r->out.flags = 0;
137                 *r->out.unkn7 = 0;
138                 return;
139         }
140
141         DEBUG(10, ("%s: path: %s\n", __func__, mds_ctx->spath));
142
143         *r->out.status = 0;
144         *r->out.flags = 0x6b000001;
145         *r->out.unkn7 = 0;
146
147         return;
148 }
149
150 void _mdssvc_cmd(struct pipes_struct *p, struct mdssvc_cmd *r)
151 {
152         bool ok;
153         char *rbuf;
154         struct mds_ctx *mds_ctx;
155         NTSTATUS status;
156
157         mds_ctx = find_policy_by_hnd(p,
158                                      r->in.handle,
159                                      DCESRV_HANDLE_ANY,
160                                      struct mds_ctx,
161                                      &status);
162         if (!NT_STATUS_IS_OK(status)) {
163                 if (ndr_policy_handle_empty(r->in.handle)) {
164                         p->fault_state = 0;
165                 } else {
166                         p->fault_state = DCERPC_NCA_S_PROTO_ERROR;
167                 }
168                 r->out.response_blob->size = 0;
169                 *r->out.fragment = 0;
170                 *r->out.unkn9 = 0;
171                 return;
172         }
173
174         DEBUG(10, ("%s: path: %s\n", __func__, mds_ctx->spath));
175
176         ok = security_token_is_sid(p->session_info->security_token,
177                                    &mds_ctx->sid);
178         if (!ok) {
179                 struct dom_sid_buf buf;
180                 DBG_WARNING("not the same sid: %s\n",
181                             dom_sid_str_buf(&mds_ctx->sid, &buf));
182                 p->fault_state = DCERPC_FAULT_ACCESS_DENIED;
183                 return;
184         }
185
186         if (geteuid() != mds_ctx->uid) {
187                 DEBUG(0, ("uid mismatch: %d/%d\n", geteuid(), mds_ctx->uid));
188                 smb_panic("uid mismatch");
189         }
190
191         if (r->in.request_blob.size > MAX_SL_FRAGMENT_SIZE) {
192                 DEBUG(1, ("%s: request size too large\n", __func__));
193                 p->fault_state = DCERPC_FAULT_CANT_PERFORM;
194                 return;
195         }
196
197         if (r->in.request_blob.length > MAX_SL_FRAGMENT_SIZE) {
198                 DEBUG(1, ("%s: request length too large\n", __func__));
199                 p->fault_state = DCERPC_FAULT_CANT_PERFORM;
200                 return;
201         }
202
203         if (r->in.max_fragment_size1 > MAX_SL_FRAGMENT_SIZE) {
204                 DEBUG(1, ("%s: request fragment size too large: %u\n",
205                           __func__, (unsigned)r->in.max_fragment_size1));
206                 p->fault_state = DCERPC_FAULT_CANT_PERFORM;
207                 return;
208         }
209
210         rbuf = talloc_zero_array(p->mem_ctx, char, r->in.max_fragment_size1);
211         if (rbuf == NULL) {
212                 p->fault_state = DCERPC_FAULT_CANT_PERFORM;
213                 return;
214         }
215         r->out.response_blob->spotlight_blob = (uint8_t *)rbuf;
216         r->out.response_blob->size = r->in.max_fragment_size1;
217
218         /* We currently don't use fragmentation at the mdssvc RPC layer */
219         *r->out.fragment = 0;
220
221         ok = mds_dispatch(mds_ctx, &r->in.request_blob, r->out.response_blob);
222         if (ok) {
223                 *r->out.unkn9 = 0;
224         } else {
225                 /* FIXME: just interpolating from AFP, needs verification */
226                 *r->out.unkn9 = UINT32_MAX;
227         }
228
229         return;
230 }
231
232 void _mdssvc_close(struct pipes_struct *p, struct mdssvc_close *r)
233 {
234         struct mds_ctx *mds_ctx;
235         NTSTATUS status;
236
237         mds_ctx = find_policy_by_hnd(p,
238                                      r->in.in_handle,
239                                      DCESRV_HANDLE_ANY,
240                                      struct mds_ctx,
241                                      &status);
242         if (!NT_STATUS_IS_OK(status)) {
243                 DBG_WARNING("invalid handle\n");
244                 if (ndr_policy_handle_empty(r->in.in_handle)) {
245                         p->fault_state = 0;
246                 } else {
247                         p->fault_state = DCERPC_NCA_S_PROTO_ERROR;
248                 }
249                 return;
250         }
251
252         DBG_DEBUG("Close mdssvc handle for path: %s\n", mds_ctx->spath);
253         TALLOC_FREE(mds_ctx);
254
255         *r->out.out_handle = *r->in.in_handle;
256         close_policy_hnd(p, r->in.in_handle);
257
258         *r->out.status = 0;
259
260         return;
261 }
262
263 static NTSTATUS mdssvc__op_init_server(struct dcesrv_context *dce_ctx,
264                 const struct dcesrv_endpoint_server *ep_server);
265
266 static NTSTATUS mdssvc__op_shutdown_server(struct dcesrv_context *dce_ctx,
267                 const struct dcesrv_endpoint_server *ep_server);
268
269 #define DCESRV_INTERFACE_MDSSVC_INIT_SERVER \
270         mdssvc_init_server
271
272 #define DCESRV_INTERFACE_MDSSVC_SHUTDOWN_SERVER \
273         mdssvc_shutdown_server
274
275 static NTSTATUS mdssvc_init_server(struct dcesrv_context *dce_ctx,
276                 const struct dcesrv_endpoint_server *ep_server)
277 {
278         struct messaging_context *msg_ctx = global_messaging_context();
279         bool ok;
280
281         ok = mds_init(msg_ctx);
282         if (!ok) {
283                 return NT_STATUS_UNSUCCESSFUL;
284         }
285
286         return mdssvc__op_init_server(dce_ctx, ep_server);
287 }
288
289 static NTSTATUS mdssvc_shutdown_server(struct dcesrv_context *dce_ctx,
290                 const struct dcesrv_endpoint_server *ep_server)
291 {
292         mds_shutdown();
293
294         return mdssvc__op_shutdown_server(dce_ctx, ep_server);
295 }
296
297 /* include the generated boilerplate */
298 #include "librpc/gen_ndr/ndr_mdssvc_scompat.c"