1 /*
2    Unix SMB/CIFS implementation.
3 
4    test suite for SMB2 leases
5 
6    Copyright (C) Zachary Loafman 2009
7 
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12 
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17 
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 */
21 
22 #include "includes.h"
23 #include <tevent.h>
24 #include "libcli/smb2/smb2.h"
25 #include "libcli/smb2/smb2_calls.h"
26 #include "torture/torture.h"
27 #include "torture/smb2/proto.h"
28 #include "torture/util.h"
29 #include "libcli/smb/smbXcli_base.h"
30 #include "lease_break_handler.h"
31 
32 struct lease_break_info lease_break_info;
33 
torture_lease_break_callback(struct smb2_request * req)34 void torture_lease_break_callback(struct smb2_request *req)
35 {
36 	NTSTATUS status;
37 
38 	status = smb2_lease_break_ack_recv(req, &lease_break_info.lease_break_ack);
39 	if (!NT_STATUS_IS_OK(status))
40 		lease_break_info.failures++;
41 
42 	return;
43 }
44 
45 /* a lease break request handler */
torture_lease_handler(struct smb2_transport * transport,const struct smb2_lease_break * lb,void * private_data)46 bool torture_lease_handler(struct smb2_transport *transport,
47 			   const struct smb2_lease_break *lb,
48 			   void *private_data)
49 {
50 	struct smb2_tree *tree = private_data;
51 	struct smb2_lease_break_ack io;
52 	struct smb2_request *req;
53 
54 	lease_break_info.lease_transport = transport;
55 	lease_break_info.lease_break = *lb;
56 	lease_break_info.count++;
57 
58 	if (lease_break_info.lease_skip_ack) {
59 		return true;
60 	}
61 
62 	if (lb->break_flags & SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED) {
63 		ZERO_STRUCT(io);
64 		io.in.lease.lease_key = lb->current_lease.lease_key;
65 		io.in.lease.lease_state = lb->new_lease_state;
66 
67 		req = smb2_lease_break_ack_send(tree, &io);
68 		req->async.fn = torture_lease_break_callback;
69 		req->async.private_data = NULL;
70 	}
71 
72 	return true;
73 }
74 
75 /*
76  * A lease break handler which ignores incoming lease break requests
77  * To be used in cases where the client is expected to ignore incoming
78  * lease break requests
79  */
torture_lease_ignore_handler(struct smb2_transport * transport,const struct smb2_lease_break * lb,void * private_data)80 bool torture_lease_ignore_handler(struct smb2_transport *transport,
81 			   const struct smb2_lease_break *lb,
82 			   void *private_data)
83 {
84 	return true;
85 }
86 
87 /*
88    Timer handler function notifies the registering function that time is up
89 */
timeout_cb(struct tevent_context * ev,struct tevent_timer * te,struct timeval current_time,void * private_data)90 static void timeout_cb(struct tevent_context *ev,
91 		       struct tevent_timer *te,
92 		       struct timeval current_time,
93 		       void *private_data)
94 {
95 	bool *timesup = (bool *)private_data;
96 	*timesup = true;
97 	return;
98 }
99 
100 /*
101    Wait a short period of time to receive a single oplock break request
102 */
torture_wait_for_lease_break(struct torture_context * tctx)103 void torture_wait_for_lease_break(struct torture_context *tctx)
104 {
105 	TALLOC_CTX *tmp_ctx = talloc_new(NULL);
106 	struct tevent_timer *te = NULL;
107 	struct timeval ne;
108 	bool timesup = false;
109 	int old_count = lease_break_info.count;
110 
111 	/* Wait 1 second for an lease break */
112 	ne = tevent_timeval_current_ofs(0, 1000000);
113 
114 	te = tevent_add_timer(tctx->ev, tmp_ctx, ne, timeout_cb, &timesup);
115 	if (te == NULL) {
116 		torture_comment(tctx, "Failed to wait for an oplock break. "
117 				      "test results may not be accurate.");
118 		goto done;
119 	}
120 
121 	while (!timesup && lease_break_info.count < old_count + 1) {
122 		if (tevent_loop_once(tctx->ev) != 0) {
123 			torture_comment(tctx, "Failed to wait for an oplock "
124 					      "break. test results may not be "
125 					      "accurate.");
126 			goto done;
127 		}
128 	}
129 
130 done:
131 	/* We don't know if the timed event fired and was freed, we received
132 	 * our oplock break, or some other event triggered the loop.  Thus,
133 	 * we create a tmp_ctx to be able to safely free/remove the timed
134 	 * event in all 3 cases. */
135 	talloc_free(tmp_ctx);
136 
137 	return;
138 }
139