smbd: use metadata_fsp() with SMB_VFS_FSET_NT_ACL()
[samba.git] / source3 / torture / test_messaging_read.c
1 /*
2    Unix SMB/CIFS implementation.
3    Test for a messaging_read bug
4    Copyright (C) Volker Lendecke 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 "torture/proto.h"
22 #include "lib/util/tevent_unix.h"
23 #include "messages.h"
24
25 struct msg_count_state {
26         struct tevent_context *ev;
27         struct messaging_context *msg_ctx;
28         uint32_t msg_type;
29         unsigned *count;
30 };
31
32 static void msg_count_done(struct tevent_req *subreq);
33
34 static struct tevent_req *msg_count_send(TALLOC_CTX *mem_ctx,
35                                          struct tevent_context *ev,
36                                          struct messaging_context *msg_ctx,
37                                          uint32_t msg_type,
38                                          unsigned *count)
39 {
40         struct tevent_req *req, *subreq;
41         struct msg_count_state *state;
42
43         req = tevent_req_create(mem_ctx, &state, struct msg_count_state);
44         if (req == NULL) {
45                 return NULL;
46         }
47         state->ev = ev;
48         state->msg_ctx = msg_ctx;
49         state->msg_type = msg_type;
50         state->count = count;
51
52         subreq = messaging_read_send(state, state->ev, state->msg_ctx,
53                                      state->msg_type);
54         if (tevent_req_nomem(subreq, req)) {
55                 return tevent_req_post(req, ev);
56         }
57         tevent_req_set_callback(subreq, msg_count_done, req);
58         return req;
59 }
60
61 static void msg_count_done(struct tevent_req *subreq)
62 {
63         struct tevent_req *req = tevent_req_callback_data(
64                 subreq, struct tevent_req);
65         struct msg_count_state *state = tevent_req_data(
66                 req, struct msg_count_state);
67         int ret;
68
69         ret = messaging_read_recv(subreq, NULL, NULL);
70         TALLOC_FREE(subreq);
71         if (tevent_req_error(req, ret)) {
72                 return;
73         }
74         *state->count += 1;
75
76         subreq = messaging_read_send(state, state->ev, state->msg_ctx,
77                                      state->msg_type);
78         if (tevent_req_nomem(subreq, req)) {
79                 return;
80         }
81         tevent_req_set_callback(subreq, msg_count_done, req);
82 }
83
84 bool run_messaging_read1(int dummy)
85 {
86         struct tevent_context *ev = NULL;
87         struct messaging_context *msg_ctx = NULL;
88         struct tevent_req *req1 = NULL;
89         unsigned count1 = 0;
90         struct tevent_req *req2 = NULL;
91         unsigned count2 = 0;
92         NTSTATUS status;
93         bool retval = false;
94         int i;
95
96         ev = samba_tevent_context_init(talloc_tos());
97         if (ev == NULL) {
98                 fprintf(stderr, "tevent_context_init failed\n");
99                 goto fail;
100         }
101         msg_ctx = messaging_init(ev, ev);
102         if (msg_ctx == NULL) {
103                 fprintf(stderr, "messaging_init failed\n");
104                 goto fail;
105         }
106
107         req1 = msg_count_send(ev, ev, msg_ctx, MSG_SMB_NOTIFY, &count1);
108         if (req1 == NULL) {
109                 fprintf(stderr, "msg_count_send failed\n");
110                 goto fail;
111         }
112         req2 = msg_count_send(ev, ev, msg_ctx, MSG_SMB_NOTIFY, &count2);
113         if (req1 == NULL) {
114                 fprintf(stderr, "msg_count_send failed\n");
115                 goto fail;
116         }
117         status = messaging_send_buf(msg_ctx, messaging_server_id(msg_ctx),
118                                     MSG_SMB_NOTIFY, NULL, 0);
119         if (!NT_STATUS_IS_OK(status)) {
120                 fprintf(stderr, "messaging_send_buf failed: %s\n",
121                         nt_errstr(status));
122                 goto fail;
123         }
124
125         for (i=0; i<2; i++) {
126                 if (tevent_loop_once(ev) != 0) {
127                         fprintf(stderr, "tevent_loop_once failed\n");
128                         goto fail;
129                 }
130         }
131
132         printf("%u/%u\n", count1, count2);
133
134         if ((count1 != 1) || (count2 != 0)) {
135                 fprintf(stderr, "Got %u/%u msgs, expected 1/0\n",
136                         count1, count2);
137                 goto fail;
138         }
139
140         retval = true;
141 fail:
142         TALLOC_FREE(req1);
143         TALLOC_FREE(req2);
144         TALLOC_FREE(msg_ctx);
145         TALLOC_FREE(ev);
146         return retval;
147 }
148
149 struct msg_free_state {
150         struct tevent_req **to_free;
151 };
152
153 static void msg_free_done(struct tevent_req *subreq);
154
155 static struct tevent_req *msg_free_send(TALLOC_CTX *mem_ctx,
156                                         struct tevent_context *ev,
157                                         struct messaging_context *msg_ctx,
158                                         uint32_t msg_type,
159                                         struct tevent_req **to_free)
160 {
161         struct tevent_req *req, *subreq;
162         struct msg_free_state *state;
163
164         req = tevent_req_create(mem_ctx, &state, struct msg_free_state);
165         if (req == NULL) {
166                 return NULL;
167         }
168         state->to_free = to_free;
169
170         subreq = messaging_read_send(state, ev, msg_ctx, msg_type);
171         if (tevent_req_nomem(subreq, req)) {
172                 return tevent_req_post(req, ev);
173         }
174         tevent_req_set_callback(subreq, msg_free_done, req);
175         return req;
176 }
177
178 static void msg_free_done(struct tevent_req *subreq)
179 {
180         struct tevent_req *req = tevent_req_callback_data(
181                 subreq, struct tevent_req);
182         struct msg_free_state *state = tevent_req_data(
183                 req, struct msg_free_state);
184         int ret;
185
186         ret = messaging_read_recv(subreq, NULL, NULL);
187         TALLOC_FREE(subreq);
188         if (tevent_req_error(req, ret)) {
189                 return;
190         }
191         TALLOC_FREE(*state->to_free);
192         tevent_req_done(req);
193 }
194
195 bool run_messaging_read2(int dummy)
196 {
197         struct tevent_context *ev = NULL;
198         struct messaging_context *msg_ctx = NULL;
199         struct tevent_req *req1 = NULL;
200         struct tevent_req *req2 = NULL;
201         unsigned count = 0;
202         NTSTATUS status;
203         bool retval = false;
204
205         ev = samba_tevent_context_init(talloc_tos());
206         if (ev == NULL) {
207                 fprintf(stderr, "tevent_context_init failed\n");
208                 goto fail;
209         }
210         msg_ctx = messaging_init(ev, ev);
211         if (msg_ctx == NULL) {
212                 fprintf(stderr, "messaging_init failed\n");
213                 goto fail;
214         }
215
216         req1 = msg_free_send(ev, ev, msg_ctx, MSG_SMB_NOTIFY, &req2);
217         if (req1 == NULL) {
218                 fprintf(stderr, "msg_count_send failed\n");
219                 goto fail;
220         }
221         req2 = msg_count_send(ev, ev, msg_ctx, MSG_SMB_NOTIFY, &count);
222         if (req1 == NULL) {
223                 fprintf(stderr, "msg_count_send failed\n");
224                 goto fail;
225         }
226         status = messaging_send_buf(msg_ctx, messaging_server_id(msg_ctx),
227                                     MSG_SMB_NOTIFY, NULL, 0);
228         if (!NT_STATUS_IS_OK(status)) {
229                 fprintf(stderr, "messaging_send_buf failed: %s\n",
230                         nt_errstr(status));
231                 goto fail;
232         }
233
234         if (!tevent_req_poll(req1, ev) != 0) {
235                 fprintf(stderr, "tevent_req_poll failed\n");
236                 goto fail;
237         }
238
239         if (count != 0) {
240                 fprintf(stderr, "Got %u msgs, expected none\n", count);
241                 goto fail;
242         }
243
244         retval = true;
245 fail:
246         TALLOC_FREE(req1);
247         TALLOC_FREE(msg_ctx);
248         TALLOC_FREE(ev);
249         return retval;
250 }
251
252 struct msg_pingpong_state {
253         struct messaging_context *msg_ctx;
254 };
255
256 static void msg_pingpong_done(struct tevent_req *subreq);
257
258 static struct tevent_req *msg_pingpong_send(TALLOC_CTX *mem_ctx,
259                                             struct tevent_context *ev,
260                                             struct server_id dst)
261 {
262         struct tevent_req *req, *subreq;
263         struct msg_pingpong_state *state;
264         NTSTATUS status;
265
266         req = tevent_req_create(mem_ctx, &state, struct msg_pingpong_state);
267         if (req == NULL) {
268                 return NULL;
269         }
270
271         if (!tevent_req_set_endtime(req, ev, timeval_current_ofs(10, 0))) {
272                 return tevent_req_post(req, ev);
273         }
274
275         state->msg_ctx = messaging_init(state, ev);
276         if (tevent_req_nomem(state->msg_ctx, req)) {
277                 return tevent_req_post(req, ev);
278         }
279
280         status = messaging_send_buf(state->msg_ctx, dst, MSG_PING, NULL, 0);
281         if (!NT_STATUS_IS_OK(status)) {
282                 DBG_DEBUG("messaging_send_buf failed: %s\n", nt_errstr(status));
283                 tevent_req_error(req, map_errno_from_nt_status(status));
284                 return tevent_req_post(req, ev);
285         }
286
287         subreq = messaging_read_send(state, ev, state->msg_ctx, MSG_PONG);
288         if (tevent_req_nomem(subreq, req)) {
289                 return tevent_req_post(req, ev);
290         }
291         tevent_req_set_callback(subreq, msg_pingpong_done, req);
292         return req;
293 }
294
295 static void msg_pingpong_done(struct tevent_req *subreq)
296 {
297         struct tevent_req *req = tevent_req_callback_data(
298                 subreq, struct tevent_req);
299         int ret;
300
301         ret = messaging_read_recv(subreq, NULL, NULL);
302         TALLOC_FREE(subreq);
303         if (ret != 0) {
304                 tevent_req_error(req, ret);
305                 return;
306         }
307         tevent_req_done(req);
308 }
309
310 static int msg_pingpong_recv(struct tevent_req *req)
311 {
312         int err;
313
314         if (tevent_req_is_unix_error(req, &err)) {
315                 return err;
316         }
317         return 0;
318 }
319
320 static int msg_pingpong(struct server_id dst)
321 {
322         struct tevent_context *ev;
323         struct tevent_req *req;
324         int ret = ENOMEM;
325
326         ev = tevent_context_init(talloc_tos());
327         if (ev == NULL) {
328                 goto fail;
329         }
330         req = msg_pingpong_send(ev, ev, dst);
331         if (req == NULL) {
332                 goto fail;
333         }
334         if (!tevent_req_poll(req, ev)) {
335                 ret = errno;
336                 goto fail;
337         }
338         ret = msg_pingpong_recv(req);
339 fail:
340         TALLOC_FREE(ev);
341         return ret;
342 }
343
344 static void ping_responder_exit(struct tevent_context *ev,
345                                 struct tevent_fd *fde,
346                                 uint16_t flags,
347                                 void *private_data)
348 {
349         bool *done = private_data;
350
351         printf("Child: received write on exit-pipe\n");
352
353         *done = true;
354 }
355
356 static void ping_responder(int ready_pipe, int exit_pipe)
357 {
358         struct tevent_context *ev;
359         struct messaging_context *msg_ctx;
360         struct tevent_fd *exit_handler;
361         char c = 0;
362         bool done = false;
363
364         ev = samba_tevent_context_init(talloc_tos());
365         if (ev == NULL) {
366                 fprintf(stderr, "child tevent_context_init failed\n");
367                 exit(1);
368         }
369         msg_ctx = messaging_init(ev, ev);
370         if (msg_ctx == NULL) {
371                 fprintf(stderr, "child messaging_init failed\n");
372                 exit(1);
373         }
374         exit_handler = tevent_add_fd(ev, ev, exit_pipe, TEVENT_FD_READ,
375                                      ping_responder_exit, &done);
376         if (exit_handler == NULL) {
377                 fprintf(stderr, "child tevent_add_fd failed\n");
378                 exit(1);
379         }
380
381         if (write(ready_pipe, &c, 1) != 1) {
382                 fprintf(stderr, "child messaging_init failed\n");
383                 exit(1);
384         }
385
386         while (!done) {
387                 int ret;
388                 ret = tevent_loop_once(ev);
389                 if (ret != 0) {
390                         fprintf(stderr, "child tevent_loop_once failed\n");
391                         exit(1);
392                 }
393         }
394
395         printf("Child: done, exiting...\n");
396
397         TALLOC_FREE(msg_ctx);
398         TALLOC_FREE(ev);
399 }
400
401 bool run_messaging_read3(int dummy)
402 {
403         struct tevent_context *ev = NULL;
404         struct messaging_context *msg_ctx = NULL;
405         bool retval = false;
406         pid_t child;
407         int ready_pipe[2];
408         int exit_pipe[2];
409         int i, ret;
410         char c;
411         struct server_id dst;
412         ssize_t written;
413
414         if ((pipe(ready_pipe) != 0) || (pipe(exit_pipe) != 0)) {
415                 perror("pipe failed");
416                 return false;
417         }
418
419         child = fork();
420         if (child == -1) {
421                 perror("fork failed");
422                 return false;
423         }
424
425         if (child == 0) {
426                 close(ready_pipe[0]);
427                 close(exit_pipe[1]);
428                 ping_responder(ready_pipe[1], exit_pipe[0]);
429                 exit(0);
430         }
431         close(ready_pipe[1]);
432         close(exit_pipe[0]);
433
434         if (read(ready_pipe[0], &c, 1) != 1) {
435                 perror("read failed");
436                 return false;
437         }
438
439         ev = samba_tevent_context_init(talloc_tos());
440         if (ev == NULL) {
441                 fprintf(stderr, "tevent_context_init failed\n");
442                 goto fail;
443         }
444
445         dst = (struct server_id){ .pid = child, .vnn = NONCLUSTER_VNN, };
446
447         for (i=0; i<100; i++) {
448                 ret = msg_pingpong(dst);
449                 if (ret != 0){
450                         fprintf(stderr, "msg_pingpong failed\n");
451                         goto fail;
452                 }
453         }
454
455         printf("Parent: telling child to exit\n");
456
457         written = write(exit_pipe[1], &c, 1);
458         if (written != 1) {
459                 perror("write to exit_pipe failed");
460                 goto fail;
461         }
462
463         ret = waitpid(child, NULL, 0);
464         if (ret == -1) {
465                 perror("waitpid failed");
466                 goto fail;
467         }
468
469         printf("Parent: child exited. Done\n");
470
471         retval = true;
472 fail:
473         TALLOC_FREE(msg_ctx);
474         TALLOC_FREE(ev);
475         return retval;
476 }
477
478 /**
479  * read4:
480  *
481  * test transferring a big payload.
482  */
483
484 #define MSG_TORTURE_READ4 0xF104
485
486 static bool read4_child(int ready_fd)
487 {
488         struct tevent_context *ev = NULL;
489         struct messaging_context *msg_ctx = NULL;
490         TALLOC_CTX *frame = talloc_stackframe();
491         bool retval = false;
492         uint8_t c = 1;
493         struct tevent_req *subreq;
494         int ret;
495         ssize_t bytes;
496         struct messaging_rec *rec;
497         bool ok;
498
499         ev = samba_tevent_context_init(frame);
500         if (ev == NULL) {
501                 fprintf(stderr, "child: tevent_context_init failed\n");
502                 goto done;
503         }
504
505         msg_ctx = messaging_init(ev, ev);
506         if (msg_ctx == NULL) {
507                 fprintf(stderr, "child: messaging_init failed\n");
508                 goto done;
509         }
510
511         printf("child: telling parent we're ready to receive messages\n");
512
513         /* Tell the parent we are ready to receive messages. */
514         bytes = write(ready_fd, &c, 1);
515         if (bytes != 1) {
516                 perror("child: failed to write to ready_fd");
517                 goto done;
518         }
519
520         printf("child: waiting for messages\n");
521
522         subreq = messaging_read_send(frame, /* TALLOC_CTX */
523                                      ev, msg_ctx,
524                                      MSG_TORTURE_READ4);
525         if (subreq == NULL) {
526                 fprintf(stderr, "child: messaging_read_send failed\n");
527                 goto done;
528         }
529
530         ok = tevent_req_poll(subreq, ev);
531         if (!ok) {
532                 fprintf(stderr, "child: tevent_req_poll failed\n");
533                 goto done;
534         }
535
536         printf("child: receiving message\n");
537
538         ret = messaging_read_recv(subreq, frame, &rec);
539         TALLOC_FREE(subreq);
540         if (ret != 0) {
541                 fprintf(stderr, "child: messaging_read_recv failed\n");
542                 goto done;
543         }
544
545         printf("child: received message\n");
546
547         /* Tell the parent we are done. */
548         bytes = write(ready_fd, &c, 1);
549         if (bytes != 1) {
550                 perror("child: failed to write to ready_fd");
551                 goto done;
552         }
553
554         printf("child: done\n");
555
556         retval = true;
557
558 done:
559         TALLOC_FREE(frame);
560         return retval;
561 }
562
563 struct child_done_state {
564         int fd;
565         bool done;
566 };
567
568 static void child_done_cb(struct tevent_context *ev,
569                           struct tevent_fd *fde,
570                           uint16_t flags,
571                           void *private_data)
572 {
573         struct child_done_state *state =
574                         (struct child_done_state *)private_data;
575         char c = 0;
576         ssize_t bytes;
577
578         bytes = read(state->fd, &c, 1);
579         if (bytes != 1) {
580                 perror("parent: read from ready_fd failed");
581         }
582
583         state->done = true;
584 }
585
586 static bool read4_parent(pid_t child_pid, int ready_fd)
587 {
588         struct tevent_context *ev = NULL;
589         struct messaging_context *msg_ctx = NULL;
590         bool retval = false;
591         int ret;
592         NTSTATUS status;
593         struct server_id dst;
594         TALLOC_CTX *frame = talloc_stackframe();
595         uint8_t c;
596         ssize_t bytes;
597         struct iovec iov;
598         DATA_BLOB blob;
599         struct tevent_fd *child_done_fde;
600         struct child_done_state child_state;
601
602         /* wait until the child is ready to receive messages */
603         bytes = read(ready_fd, &c, 1);
604         if (bytes != 1) {
605                 perror("parent: read from ready_fd failed");
606                 goto done;
607         }
608
609         printf("parent: child is ready to receive messages\n");
610
611         ev = samba_tevent_context_init(frame);
612         if (ev == NULL) {
613                 fprintf(stderr, "parent: tevent_context_init failed\n");
614                 goto done;
615         }
616
617         msg_ctx = messaging_init(ev, ev);
618         if (msg_ctx == NULL) {
619                 fprintf(stderr, "parent: messaging_init failed\n");
620                 goto done;
621         }
622
623         child_state.fd = ready_fd;
624         child_state.done = false;
625
626         child_done_fde = tevent_add_fd(ev, ev, ready_fd, TEVENT_FD_READ,
627                                        child_done_cb, &child_state);
628         if (child_done_fde == NULL) {
629                 fprintf(stderr,
630                         "parent: failed tevent_add_fd for child done\n");
631                 goto done;
632         }
633
634         /*
635          * Send a 1M payload with the message.
636          */
637         blob = data_blob_talloc_zero(frame, 1000*1000);
638         iov.iov_base = blob.data;
639         iov.iov_len  = blob.length;
640
641         dst = messaging_server_id(msg_ctx);
642         dst.pid = child_pid;
643
644         printf("parent: sending message to child\n");
645
646         status = messaging_send_iov(msg_ctx, dst, MSG_TORTURE_READ4, &iov, 1,
647                                     NULL, 0);
648         if (!NT_STATUS_IS_OK(status)) {
649                 fprintf(stderr, "parent: messaging_send_iov failed: %s\n",
650                         nt_errstr(status));
651                 goto done;
652         }
653
654         printf("parent: waiting for child to confirm\n");
655
656         while (!child_state.done) {
657                 ret = tevent_loop_once(ev);
658                 if (ret != 0) {
659                         fprintf(stderr, "parent: tevent_loop_once failed\n");
660                         goto done;
661                 }
662         }
663
664         printf("parent: child confirmed\n");
665
666         ret = waitpid(child_pid, NULL, 0);
667         if (ret == -1) {
668                 perror("parent: waitpid failed");
669                 goto done;
670         }
671
672         printf("parent: done\n");
673
674         retval = true;
675
676 done:
677         TALLOC_FREE(frame);
678         return retval;
679 }
680
681 bool run_messaging_read4(int dummy)
682 {
683         bool retval = false;
684         pid_t child_pid;
685         int ready_pipe[2];
686         int ret;
687
688         ret = pipe(ready_pipe);
689         if (ret != 0) {
690                 perror("parent: pipe failed for ready_pipe");
691                 return retval;
692         }
693
694         child_pid = fork();
695         if (child_pid == -1) {
696                 perror("fork failed");
697         } else if (child_pid == 0) {
698                 close(ready_pipe[0]);
699                 retval = read4_child(ready_pipe[1]);
700         } else {
701                 close(ready_pipe[1]);
702                 retval = read4_parent(child_pid, ready_pipe[0]);
703         }
704
705         return retval;
706 }