s4-smbtorture: remove unneeded ncaclrpc dir setup from RPC-SPOOLSS-NOTIFY.
[abartlet/samba.git/.git] / source4 / torture / rpc / spoolss_notify.c
1 /*
2    Unix SMB/CIFS implementation.
3    test suite for spoolss rpc notify operations
4
5    Copyright (C) Jelmer Vernooij 2007
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include "includes.h"
23 #include "system/filesys.h"
24 #include "torture/rpc/rpc.h"
25 #include "librpc/gen_ndr/ndr_spoolss_c.h"
26 #include "librpc/gen_ndr/ndr_spoolss.h"
27 #include "rpc_server/dcerpc_server.h"
28 #include "rpc_server/service_rpc.h"
29 #include "smbd/process_model.h"
30 #include "smb_server/smb_server.h"
31 #include "lib/socket/netif.h"
32 #include "ntvfs/ntvfs.h"
33 #include "param/param.h"
34
35 static NTSTATUS spoolss__op_bind(struct dcesrv_call_state *dce_call, const struct dcesrv_interface *iface)
36 {
37         return NT_STATUS_OK;
38 }
39
40 static void spoolss__op_unbind(struct dcesrv_connection_context *context, const struct dcesrv_interface *iface)
41 {
42 }
43
44 static NTSTATUS spoolss__op_ndr_pull(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct ndr_pull *pull, void **r)
45 {
46         enum ndr_err_code ndr_err;
47         uint16_t opnum = dce_call->pkt.u.request.opnum;
48
49         dce_call->fault_code = 0;
50
51         if (opnum >= ndr_table_spoolss.num_calls) {
52                 dce_call->fault_code = DCERPC_FAULT_OP_RNG_ERROR;
53                 return NT_STATUS_NET_WRITE_FAULT;
54         }
55
56         *r = talloc_size(mem_ctx, ndr_table_spoolss.calls[opnum].struct_size);
57         NT_STATUS_HAVE_NO_MEMORY(*r);
58
59         /* unravel the NDR for the packet */
60         ndr_err = ndr_table_spoolss.calls[opnum].ndr_pull(pull, NDR_IN, *r);
61         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
62                 dcerpc_log_packet(dce_call->conn->packet_log_dir,
63                                                   &ndr_table_spoolss, opnum, NDR_IN,
64                                   &dce_call->pkt.u.request.stub_and_verifier);
65                 dce_call->fault_code = DCERPC_FAULT_NDR;
66                 return NT_STATUS_NET_WRITE_FAULT;
67         }
68
69         return NT_STATUS_OK;
70 }
71
72 /* Note that received_packets are allocated in talloc_autofree_context(),
73  * because no other context appears to stay around long enough. */
74 static struct received_packet {
75         uint16_t opnum;
76         void *r;
77         struct received_packet *prev, *next;
78 } *received_packets = NULL;
79
80 static WERROR _spoolss_ReplyOpenPrinter(struct dcesrv_call_state *dce_call,
81                                         TALLOC_CTX *mem_ctx,
82                                         struct spoolss_ReplyOpenPrinter *r)
83 {
84         DEBUG(1,("_spoolss_ReplyOpenPrinter\n"));
85
86         NDR_PRINT_IN_DEBUG(spoolss_ReplyOpenPrinter, r);
87
88         r->out.handle = talloc(r, struct policy_handle);
89         r->out.handle->handle_type = 42;
90         r->out.handle->uuid = GUID_random();
91         r->out.result = WERR_OK;
92
93         NDR_PRINT_OUT_DEBUG(spoolss_ReplyOpenPrinter, r);
94
95         return WERR_OK;
96 }
97
98 static WERROR _spoolss_ReplyClosePrinter(struct dcesrv_call_state *dce_call,
99                                          TALLOC_CTX *mem_ctx,
100                                          struct spoolss_ReplyClosePrinter *r)
101 {
102         DEBUG(1,("_spoolss_ReplyClosePrinter\n"));
103
104         NDR_PRINT_IN_DEBUG(spoolss_ReplyClosePrinter, r);
105
106         ZERO_STRUCTP(r->out.handle);
107         r->out.result = WERR_OK;
108
109         NDR_PRINT_OUT_DEBUG(spoolss_ReplyClosePrinter, r);
110
111         return WERR_OK;
112 }
113
114 static NTSTATUS spoolss__op_dispatch(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, void *r)
115 {
116         uint16_t opnum = dce_call->pkt.u.request.opnum;
117         struct received_packet *rp;
118
119         rp = talloc_zero(talloc_autofree_context(), struct received_packet);
120         rp->opnum = opnum;
121         rp->r = talloc_reference(rp, r);
122
123         DLIST_ADD_END(received_packets, rp, struct received_packet *);
124
125         switch (opnum) {
126         case 58: {
127                 struct spoolss_ReplyOpenPrinter *r2 = (struct spoolss_ReplyOpenPrinter *)r;
128                 r2->out.result = _spoolss_ReplyOpenPrinter(dce_call, mem_ctx, r2);
129                 break;
130         }
131         case 60: {
132                 struct spoolss_ReplyClosePrinter *r2 = (struct spoolss_ReplyClosePrinter *)r;
133                 r2->out.result = _spoolss_ReplyClosePrinter(dce_call, mem_ctx, r2);
134                 break;
135         }
136
137         default:
138                 dce_call->fault_code = DCERPC_FAULT_OP_RNG_ERROR;
139                 break;
140         }
141
142         if (dce_call->fault_code != 0) {
143                 dcerpc_log_packet(dce_call->conn->packet_log_dir,
144                                                   &ndr_table_spoolss, opnum, NDR_IN,
145                                   &dce_call->pkt.u.request.stub_and_verifier);
146                 return NT_STATUS_NET_WRITE_FAULT;
147         }
148         return NT_STATUS_OK;
149 }
150
151
152 static NTSTATUS spoolss__op_reply(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, void *r)
153 {
154         return NT_STATUS_OK;
155 }
156
157
158 static NTSTATUS spoolss__op_ndr_push(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct ndr_push *push, const void *r)
159 {
160         enum ndr_err_code ndr_err;
161         uint16_t opnum = dce_call->pkt.u.request.opnum;
162
163         ndr_err = ndr_table_spoolss.calls[opnum].ndr_push(push, NDR_OUT, r);
164         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
165                 dce_call->fault_code = DCERPC_FAULT_NDR;
166                 return NT_STATUS_NET_WRITE_FAULT;
167         }
168
169         return NT_STATUS_OK;
170 }
171
172 const static struct dcesrv_interface notify_test_spoolss_interface = {
173         .name           = "spoolss",
174         .syntax_id  = {{0x12345678,0x1234,0xabcd,{0xef,0x00},{0x01,0x23,0x45,0x67,0x89,0xab}},1.0},
175         .bind           = spoolss__op_bind,
176         .unbind         = spoolss__op_unbind,
177         .ndr_pull       = spoolss__op_ndr_pull,
178         .dispatch       = spoolss__op_dispatch,
179         .reply          = spoolss__op_reply,
180         .ndr_push       = spoolss__op_ndr_push
181 };
182
183 static bool spoolss__op_interface_by_uuid(struct dcesrv_interface *iface, const struct GUID *uuid, uint32_t if_version)
184 {
185         if (notify_test_spoolss_interface.syntax_id.if_version == if_version &&
186                 GUID_equal(&notify_test_spoolss_interface.syntax_id.uuid, uuid)) {
187                 memcpy(iface,&notify_test_spoolss_interface, sizeof(*iface));
188                 return true;
189         }
190
191         return false;
192 }
193
194 static bool spoolss__op_interface_by_name(struct dcesrv_interface *iface, const char *name)
195 {
196         if (strcmp(notify_test_spoolss_interface.name, name)==0) {
197                 memcpy(iface, &notify_test_spoolss_interface, sizeof(*iface));
198                 return true;
199         }
200
201         return false;
202 }
203
204 static NTSTATUS spoolss__op_init_server(struct dcesrv_context *dce_ctx, const struct dcesrv_endpoint_server *ep_server)
205 {
206         int i;
207
208         for (i=0;i<ndr_table_spoolss.endpoints->count;i++) {
209                 NTSTATUS ret;
210                 const char *name = ndr_table_spoolss.endpoints->names[i];
211
212                 ret = dcesrv_interface_register(dce_ctx, name, &notify_test_spoolss_interface, NULL);
213                 if (!NT_STATUS_IS_OK(ret)) {
214                         DEBUG(1,("spoolss_op_init_server: failed to register endpoint '%s'\n",name));
215                         return ret;
216                 }
217         }
218
219         return NT_STATUS_OK;
220 }
221
222 static bool test_RFFPCNEx(struct torture_context *tctx,
223                           struct dcerpc_pipe *p)
224 {
225         struct spoolss_OpenPrinter q;
226         struct spoolss_RemoteFindFirstPrinterChangeNotifyEx r;
227         struct dcesrv_endpoint_server ep_server;
228         NTSTATUS status;
229         struct dcesrv_context *dce_ctx;
230         const char *endpoints[] = { "spoolss", NULL };
231         struct dcesrv_endpoint *e;
232         struct spoolss_NotifyOption t1;
233         struct spoolss_ClosePrinter cp;
234         struct received_packet *rp;
235
236         struct policy_handle handle;
237         const char *address;
238         struct interface *ifaces;
239
240         received_packets = NULL;
241
242         ntvfs_init(tctx->lp_ctx);
243
244         ZERO_STRUCT(q);
245
246         q.in.printername        = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
247         q.in.datatype           = NULL;
248         q.in.devmode_ctr.devmode= NULL;
249         q.in.access_mask        = SEC_FLAG_MAXIMUM_ALLOWED;
250         q.out.handle            = &handle;
251
252         torture_comment(tctx, "Testing OpenPrinter(%s)\n", q.in.printername);
253
254         status = dcerpc_spoolss_OpenPrinter(p, tctx, &q);
255
256         torture_assert_ntstatus_ok(tctx, status, "OpenPrinter failed");
257
258         torture_assert_werr_ok(tctx, q.out.result, "OpenPrinter failed");
259
260         /* Start DCE/RPC server */
261
262         /* fill in our name */
263         ep_server.name = "spoolss";
264
265         /* fill in all the operations */
266         ep_server.init_server = spoolss__op_init_server;
267
268         ep_server.interface_by_uuid = spoolss__op_interface_by_uuid;
269         ep_server.interface_by_name = spoolss__op_interface_by_name;
270
271         torture_assert_ntstatus_ok(tctx, dcerpc_register_ep_server(&ep_server),
272                                   "unable to register spoolss server");
273
274         lp_set_cmdline(tctx->lp_ctx, "dcerpc endpoint servers", "spoolss");
275
276         load_interfaces(tctx, lp_interfaces(tctx->lp_ctx), &ifaces);
277         address = iface_n_ip(ifaces, 0);
278         torture_comment(tctx, "Listening for callbacks on %s\n", address);
279         status = smbsrv_add_socket(p->conn->event_ctx, tctx->lp_ctx, &single_ops, address);
280         torture_assert_ntstatus_ok(tctx, status, "starting smb server");
281
282         status = dcesrv_init_context(tctx, tctx->lp_ctx, endpoints, &dce_ctx);
283         torture_assert_ntstatus_ok(tctx, status,
284                                    "unable to initialize DCE/RPC server");
285
286         for (e=dce_ctx->endpoint_list;e;e=e->next) {
287                 status = dcesrv_add_ep(dce_ctx, tctx->lp_ctx,
288                                        e, tctx->ev, &single_ops);
289                 torture_assert_ntstatus_ok(tctx, status,
290                                 "unable listen on dcerpc endpoint server");
291         }
292
293         r.in.flags = 0;
294         r.in.local_machine = talloc_asprintf(tctx, "\\\\%s", address);
295         r.in.options = 0;
296         r.in.printer_local = 123;
297         t1.version = 2;
298         t1.flags = 0;
299         t1.count = 2;
300         t1.types = talloc_zero_array(tctx, struct spoolss_NotifyOptionType, 2);
301         t1.types[0].type = PRINTER_NOTIFY_TYPE;
302         t1.types[0].count = 1;
303         t1.types[0].fields = talloc_array(t1.types, union spoolss_Field, 1);
304         t1.types[0].fields[0].field = PRINTER_NOTIFY_FIELD_SERVER_NAME;
305
306         t1.types[1].type = JOB_NOTIFY_TYPE;
307         t1.types[1].count = 1;
308         t1.types[1].fields = talloc_array(t1.types, union spoolss_Field, 1);
309         t1.types[1].fields[0].field = PRINTER_NOTIFY_FIELD_PRINTER_NAME;
310
311         r.in.notify_options = &t1;
312         r.in.handle = &handle;
313
314         status = dcerpc_spoolss_RemoteFindFirstPrinterChangeNotifyEx(p, tctx, &r);
315
316         torture_assert_ntstatus_ok(tctx, status, "FFPCNEx failed");
317
318         torture_assert_werr_ok(tctx, r.out.result, "error return code for FFPCNEx");
319
320         cp.in.handle = &handle;
321         cp.out.handle = &handle;
322
323         torture_comment(tctx, "Testing ClosePrinter\n");
324
325         status = dcerpc_spoolss_ClosePrinter(p, tctx, &cp);
326         torture_assert_ntstatus_ok(tctx, status, "ClosePrinter failed");
327
328         /* We should've had an incoming packet 58 (ReplyOpenPrinter) or 60
329          * (ReplyClosePrinter) */
330
331         torture_assert(tctx, received_packets != NULL, "no packets received");
332
333         for (rp = received_packets; rp; rp = rp->next) {
334                 switch (rp->opnum) {
335                 case 58:
336                 case 60:
337                         continue;
338                 default:
339                         torture_fail(tctx,
340                                 talloc_asprintf(tctx, "unexpected packet opnum %d received", rp->opnum));
341                 }
342         }
343
344         /* Shut down DCE/RPC server */
345         talloc_free(dce_ctx);
346
347         return true;
348 }
349
350 /** Test that makes sure that calling ReplyOpenPrinter()
351  * on Samba 4 will cause an irpc broadcast call.
352  */
353 static bool test_ReplyOpenPrinter(struct torture_context *tctx,
354                                   struct dcerpc_pipe *p)
355 {
356         struct spoolss_ReplyOpenPrinter r;
357         struct spoolss_ReplyClosePrinter s;
358         struct policy_handle h;
359
360         if (torture_setting_bool(tctx, "samba3", false)) {
361                 torture_skip(tctx, "skipping ReplyOpenPrinter server implementation test against s3\n");
362         }
363
364         r.in.server_name = "earth";
365         r.in.printer_local = 2;
366         r.in.type = REG_DWORD;
367         r.in.bufsize = 0;
368         r.in.buffer = NULL;
369         r.out.handle = &h;
370
371         torture_assert_ntstatus_ok(tctx,
372                         dcerpc_spoolss_ReplyOpenPrinter(p, tctx, &r),
373                         "spoolss_ReplyOpenPrinter call failed");
374
375         torture_assert_werr_ok(tctx, r.out.result, "error return code");
376
377         s.in.handle = &h;
378         s.out.handle = &h;
379
380         torture_assert_ntstatus_ok(tctx,
381                         dcerpc_spoolss_ReplyClosePrinter(p, tctx, &s),
382                         "spoolss_ReplyClosePrinter call failed");
383
384         torture_assert_werr_ok(tctx, r.out.result, "error return code");
385
386         return true;
387 }
388
389 struct torture_suite *torture_rpc_spoolss_notify(TALLOC_CTX *mem_ctx)
390 {
391         struct torture_suite *suite = torture_suite_create(mem_ctx, "SPOOLSS-NOTIFY");
392
393         struct torture_rpc_tcase *tcase = torture_suite_add_rpc_iface_tcase(suite,
394                                                         "notify", &ndr_table_spoolss);
395
396         torture_rpc_tcase_add_test(tcase, "testRFFPCNEx", test_RFFPCNEx);
397         torture_rpc_tcase_add_test(tcase, "testReplyOpenPrinter", test_ReplyOpenPrinter);
398
399         return suite;
400 }