37b13e79a0bbee8af8975bfe114efd3646eccb72
[garming/samba-autobuild/.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 "ntdomain.h"
22 #include "rpc_server/rpc_service_setup.h"
23 #include "rpc_server/rpc_config.h"
24 #include "rpc_server/rpc_modules.h"
25 #include "rpc_server/mdssvc/srv_mdssvc_nt.h"
26 #include "../librpc/gen_ndr/srv_mdssvc.h"
27 #include "libcli/security/security_token.h"
28 #include "gen_ndr/auth.h"
29 #include "mdssvc.h"
30
31 #undef DBGC_CLASS
32 #define DBGC_CLASS DBGC_RPC_SRV
33
34 static bool mdssvc_init_cb(void *ptr)
35 {
36         struct messaging_context *msg_ctx =
37                 talloc_get_type_abort(ptr, struct messaging_context);
38         bool ok;
39
40         ok = init_service_mdssvc(msg_ctx);
41         if (!ok) {
42                 return false;
43         }
44
45         return true;
46 }
47
48 static bool mdssvc_shutdown_cb(void *ptr)
49 {
50         shutdown_service_mdssvc();
51
52         return true;
53 }
54
55 static bool rpc_setup_mdssvc(struct tevent_context *ev_ctx,
56                              struct messaging_context *msg_ctx)
57 {
58         const struct ndr_interface_table *t = &ndr_table_mdssvc;
59         const char *pipe_name = "mdssvc";
60         struct rpc_srv_callbacks mdssvc_cb;
61         NTSTATUS status;
62         enum rpc_service_mode_e service_mode = rpc_service_mode(t->name);
63         enum rpc_daemon_type_e mdssvc_type = rpc_mdssd_daemon();
64
65         mdssvc_cb.init         = mdssvc_init_cb;
66         mdssvc_cb.shutdown     = mdssvc_shutdown_cb;
67         mdssvc_cb.private_data = msg_ctx;
68
69         status = rpc_mdssvc_init(&mdssvc_cb);
70         if (!NT_STATUS_IS_OK(status)) {
71                 return false;
72         }
73
74         if (service_mode != RPC_SERVICE_MODE_EMBEDDED
75             || mdssvc_type != RPC_DAEMON_EMBEDDED) {
76                 return true;
77         }
78
79         return rpc_setup_embedded(ev_ctx, msg_ctx, t, pipe_name);
80 }
81
82 static struct rpc_module_fns rpc_module_mdssvc_fns = {
83         .setup = rpc_setup_mdssvc,
84         .init = rpc_mdssvc_init,
85         .shutdown = rpc_mdssvc_shutdown,
86 };
87
88 static_decl_rpc;
89 NTSTATUS rpc_mdssvc_module_init(void)
90 {
91         DBG_DEBUG("Registering mdsvc RPC service\n");
92
93         return register_rpc_module(&rpc_module_mdssvc_fns, "mdssvc");
94 }
95
96
97 bool init_service_mdssvc(struct messaging_context *msg_ctx)
98 {
99         return mds_init(msg_ctx);
100 }
101
102 bool shutdown_service_mdssvc(void)
103 {
104         return mds_shutdown();
105 }
106
107 static NTSTATUS create_mdssvc_policy_handle(TALLOC_CTX *mem_ctx,
108                                             struct pipes_struct *p,
109                                             const char *path,
110                                             struct policy_handle *handle)
111 {
112         struct mds_ctx *mds_ctx;
113
114         ZERO_STRUCTP(handle);
115
116         mds_ctx = mds_init_ctx(mem_ctx, p->session_info, path);
117         if (mds_ctx == NULL) {
118                 DEBUG(1, ("error in mds_init_ctx for: %s\n", path));
119                 return NT_STATUS_UNSUCCESSFUL;
120         }
121
122         if (!create_policy_hnd(p, handle, mds_ctx)) {
123                 talloc_free(mds_ctx);
124                 ZERO_STRUCTP(handle);
125                 return NT_STATUS_NO_MEMORY;
126         }
127
128         return NT_STATUS_OK;
129 }
130
131 void _mdssvc_open(struct pipes_struct *p, struct mdssvc_open *r)
132 {
133         int snum;
134         char *path;
135         NTSTATUS status;
136
137         DEBUG(10, ("%s: [%s]\n", __func__, r->in.share_name));
138
139         snum = lp_servicenumber(r->in.share_name);
140         if (!VALID_SNUM(snum)) {
141                 p->fault_state = DCERPC_FAULT_CANT_PERFORM;
142                 return;
143         }
144
145         if (lp_spotlight(snum)) {
146                 DEBUG(10, ("Spotlight enabled: %s\n", r->in.share_name));
147
148                 path = lp_path(talloc_tos(), snum);
149                 if (path == NULL) {
150                         DEBUG(1, ("Couldn't create policy handle for %s\n",
151                                   r->in.share_name));
152                         p->fault_state = DCERPC_FAULT_CANT_PERFORM;
153                         return;
154                 }
155
156                 status = create_mdssvc_policy_handle(p->mem_ctx, p, path,
157                                                      r->out.handle);
158                 if (!NT_STATUS_IS_OK(status)) {
159                         DEBUG(1, ("Couldn't create policy handle for %s\n",
160                                   r->in.share_name));
161                         talloc_free(path);
162                         p->fault_state = DCERPC_FAULT_CANT_PERFORM;
163                         return;
164                 }
165
166                 strlcpy(discard_const_p(char, r->out.share_path), path, 1024);
167                 talloc_free(path);
168                 *r->out.device_id = *r->in.device_id;
169         }
170
171         *r->out.unkn2 = 0x17;
172         *r->out.unkn3 = 0;
173
174         return;
175 }
176
177 void _mdssvc_unknown1(struct pipes_struct *p, struct mdssvc_unknown1 *r)
178 {
179         struct mds_ctx *mds_ctx;
180
181         if (!find_policy_by_hnd(p, &r->in.handle, (void **)(void *)&mds_ctx)) {
182                 DEBUG(1, ("%s: invalid handle\n", __func__));
183                 return;
184         }
185
186         DEBUG(10, ("%s: path: %s\n", __func__, mds_ctx->spath));
187
188         *r->out.status = 0;
189         *r->out.flags = 0x6b000001;
190         *r->out.unkn7 = 0;
191
192         return;
193 }
194
195 void _mdssvc_cmd(struct pipes_struct *p, struct mdssvc_cmd *r)
196 {
197         bool ok;
198         char *rbuf;
199         struct mds_ctx *mds_ctx;
200
201         if (!find_policy_by_hnd(p, &r->in.handle, (void **)(void *)&mds_ctx)) {
202                 DEBUG(1, ("%s: invalid handle\n", __func__));
203                 return;
204         }
205
206         DEBUG(10, ("%s: path: %s\n", __func__, mds_ctx->spath));
207
208         ok = security_token_is_sid(p->session_info->security_token,
209                                    &mds_ctx->sid);
210         if (!ok) {
211                 DEBUG(1,("%s: not the same sid: %s\n", __func__,
212                          sid_string_tos(&mds_ctx->sid)));
213                 p->fault_state = DCERPC_FAULT_ACCESS_DENIED;
214                 return;
215         }
216
217         if (geteuid() != mds_ctx->uid) {
218                 DEBUG(0, ("uid mismatch: %d/%d\n", geteuid(), mds_ctx->uid));
219                 smb_panic("uid mismatch");
220         }
221
222         if (r->in.request_blob.size > MAX_SL_FRAGMENT_SIZE) {
223                 DEBUG(1, ("%s: request size too large\n", __func__));
224                 p->fault_state = DCERPC_FAULT_CANT_PERFORM;
225                 return;
226         }
227
228         if (r->in.request_blob.length > MAX_SL_FRAGMENT_SIZE) {
229                 DEBUG(1, ("%s: request length too large\n", __func__));
230                 p->fault_state = DCERPC_FAULT_CANT_PERFORM;
231                 return;
232         }
233
234         if (r->in.max_fragment_size1 > MAX_SL_FRAGMENT_SIZE) {
235                 DEBUG(1, ("%s: request fragment size too large: %u\n",
236                           __func__, (unsigned)r->in.max_fragment_size1));
237                 p->fault_state = DCERPC_FAULT_CANT_PERFORM;
238                 return;
239         }
240
241         rbuf = talloc_zero_array(p->mem_ctx, char, r->in.max_fragment_size1);
242         if (rbuf == NULL) {
243                 p->fault_state = DCERPC_FAULT_CANT_PERFORM;
244                 return;
245         }
246         r->out.response_blob->spotlight_blob = (uint8_t *)rbuf;
247         r->out.response_blob->size = r->in.max_fragment_size1;
248
249         ok = mds_dispatch(mds_ctx, &r->in.request_blob, r->out.response_blob);
250         if (ok) {
251                 *r->out.status = 0;
252                 *r->out.unkn9 = 0;
253         } else {
254                 /* FIXME: just interpolating from AFP, needs verification */
255                 *r->out.status = UINT32_MAX;
256                 *r->out.unkn9 = UINT32_MAX;
257         }
258
259         return;
260 }
261
262 void _mdssvc_close(struct pipes_struct *p, struct mdssvc_close *r)
263 {
264         struct mds_ctx *mds_ctx;
265
266         if (!find_policy_by_hnd(p, &r->in.in_handle, (void **)(void *)&mds_ctx)) {
267                 DEBUG(1, ("%s: invalid handle\n", __func__));
268                 return;
269         }
270
271         DEBUG(10, ("%s: path: %s\n", __func__, mds_ctx->spath));
272
273         close_policy_hnd(p, &r->in.in_handle);
274
275         ZERO_STRUCTP(r->out.out_handle);
276         *r->out.status = 0;
277
278         return;
279 }