Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 : Manage connections_struct structures
4 : Copyright (C) Andrew Tridgell 1998
5 : Copyright (C) Alexander Bokovoy 2002
6 : Copyright (C) Jeremy Allison 2010
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 "smbd/smbd.h"
24 : #include "smbd/globals.h"
25 : #include "rpc_server/rpc_pipes.h"
26 : #include "lib/util/tevent_ntstatus.h"
27 :
28 : /****************************************************************************
29 : Update last used timestamps.
30 : ****************************************************************************/
31 :
32 977 : static void conn_lastused_update(struct smbd_server_connection *sconn,time_t t)
33 : {
34 : struct connection_struct *conn;
35 :
36 1955 : for (conn=sconn->connections; conn; conn=conn->next) {
37 : /* Update if connection wasn't idle. */
38 978 : if (conn->lastused != conn->lastused_count) {
39 109 : conn->lastused = t;
40 109 : conn->lastused_count = t;
41 : }
42 : }
43 977 : }
44 :
45 : /****************************************************************************
46 : Idle inactive connections.
47 : ****************************************************************************/
48 :
49 977 : bool conn_idle_all(struct smbd_server_connection *sconn, time_t t)
50 : {
51 977 : int deadtime = lp_deadtime()*60;
52 : struct connection_struct *conn;
53 :
54 977 : conn_lastused_update(sconn, t);
55 :
56 977 : if (deadtime <= 0) {
57 0 : return false;
58 : }
59 :
60 979 : for (conn=sconn->connections;conn;conn=conn->next) {
61 977 : time_t age = t - conn->lastused;
62 :
63 977 : if (conn->num_files_open > 0 || age < deadtime) {
64 975 : return false;
65 : }
66 : }
67 :
68 : /*
69 : * Check all pipes for any open handles. We cannot
70 : * idle with a handle open.
71 : */
72 2 : if (check_open_pipes()) {
73 0 : return false;
74 : }
75 :
76 2 : return true;
77 : }
78 :
79 : /****************************************************************************
80 : Forcibly unmount a share - async
81 : All instances of the parameter 'sharename' share are unmounted.
82 : The special sharename '*' forces unmount of all shares.
83 : ****************************************************************************/
84 :
85 : static struct tevent_req *conn_force_tdis_send(connection_struct *conn);
86 : static void conn_force_tdis_done(struct tevent_req *req);
87 :
88 80 : void conn_force_tdis(
89 : struct smbd_server_connection *sconn,
90 : bool (*check_fn)(struct connection_struct *conn,
91 : void *private_data),
92 : void *private_data)
93 : {
94 : connection_struct *conn;
95 :
96 : /* SMB1 and SMB 2*/
97 162 : for (conn = sconn->connections; conn; conn = conn->next) {
98 : struct smbXsrv_tcon *tcon;
99 82 : bool do_close = false;
100 : struct tevent_req *req;
101 :
102 82 : if (conn->tcon == NULL) {
103 0 : continue;
104 : }
105 82 : tcon = conn->tcon;
106 :
107 82 : if (!NT_STATUS_IS_OK(tcon->status)) {
108 : /* In the process of already being disconnected. */
109 0 : continue;
110 : }
111 :
112 82 : do_close = check_fn(conn, private_data);
113 82 : if (!do_close) {
114 76 : continue;
115 : }
116 :
117 6 : req = conn_force_tdis_send(conn);
118 6 : if (req == NULL) {
119 0 : DBG_WARNING("talloc_fail forcing async close of "
120 : "share '%s'\n",
121 : tcon->global->share_name);
122 0 : continue;
123 : }
124 :
125 6 : DBG_WARNING("Forcing close of "
126 : "share '%s' (wire_id=0x%08x)\n",
127 : tcon->global->share_name,
128 : tcon->global->tcon_wire_id);
129 :
130 6 : tevent_req_set_callback(req, conn_force_tdis_done, conn);
131 : }
132 80 : }
133 :
134 : struct conn_force_tdis_state {
135 : struct tevent_queue *wait_queue;
136 : };
137 :
138 : static void conn_force_tdis_wait_done(struct tevent_req *subreq);
139 :
140 6 : static struct tevent_req *conn_force_tdis_send(connection_struct *conn)
141 : {
142 : struct tevent_req *req;
143 : struct conn_force_tdis_state *state;
144 : struct tevent_req *subreq;
145 : files_struct *fsp;
146 :
147 : /* Create this off the NULL context. We must clean up on return. */
148 6 : req = tevent_req_create(NULL, &state,
149 : struct conn_force_tdis_state);
150 6 : if (req == NULL) {
151 0 : return NULL;
152 : }
153 6 : state->wait_queue = tevent_queue_create(state,
154 : "conn_force_tdis_wait_queue");
155 6 : if (tevent_req_nomem(state->wait_queue, req)) {
156 0 : TALLOC_FREE(req);
157 0 : return NULL;
158 : }
159 :
160 : /*
161 : * Make sure that no new request will be able to use this tcon.
162 : * This ensures that once all outstanding fsp->aio_requests
163 : * on this tcon are done, we are safe to close it.
164 : */
165 6 : conn->tcon->status = NT_STATUS_NETWORK_NAME_DELETED;
166 :
167 12 : for (fsp = conn->sconn->files; fsp; fsp = fsp->next) {
168 6 : if (fsp->conn != conn) {
169 2 : continue;
170 : }
171 : /*
172 : * Flag the file as close in progress.
173 : * This will prevent any more IO being
174 : * done on it. Not strictly needed, but
175 : * doesn't hurt to flag it as closing.
176 : */
177 4 : fsp->fsp_flags.closing = true;
178 :
179 4 : if (fsp->num_aio_requests > 0) {
180 : /*
181 : * Now wait until all aio requests on this fsp are
182 : * finished.
183 : *
184 : * We don't set a callback, as we just want to block the
185 : * wait queue and the talloc_free() of fsp->aio_request
186 : * will remove the item from the wait queue.
187 : */
188 4 : subreq = tevent_queue_wait_send(fsp->aio_requests,
189 2 : conn->sconn->ev_ctx,
190 2 : state->wait_queue);
191 2 : if (tevent_req_nomem(subreq, req)) {
192 0 : TALLOC_FREE(req);
193 0 : return NULL;
194 : }
195 : }
196 : }
197 : /*
198 : * Now we add our own waiter to the end of the queue,
199 : * this way we get notified when all pending requests are finished
200 : * and reply to the outstanding SMB1 request.
201 : */
202 12 : subreq = tevent_queue_wait_send(state,
203 6 : conn->sconn->ev_ctx,
204 6 : state->wait_queue);
205 6 : if (tevent_req_nomem(subreq, req)) {
206 0 : TALLOC_FREE(req);
207 0 : return NULL;
208 : }
209 :
210 6 : tevent_req_set_callback(subreq, conn_force_tdis_wait_done, req);
211 6 : return req;
212 : }
213 :
214 6 : static void conn_force_tdis_wait_done(struct tevent_req *subreq)
215 : {
216 6 : struct tevent_req *req = tevent_req_callback_data(
217 : subreq, struct tevent_req);
218 :
219 6 : tevent_queue_wait_recv(subreq);
220 6 : TALLOC_FREE(subreq);
221 6 : tevent_req_done(req);
222 6 : }
223 :
224 6 : static NTSTATUS conn_force_tdis_recv(struct tevent_req *req)
225 : {
226 6 : return tevent_req_simple_recv_ntstatus(req);
227 : }
228 :
229 6 : static void conn_force_tdis_done(struct tevent_req *req)
230 : {
231 6 : connection_struct *conn = tevent_req_callback_data(
232 : req, connection_struct);
233 : NTSTATUS status;
234 6 : uint64_t vuid = UID_FIELD_INVALID;
235 6 : struct smbXsrv_tcon *tcon = conn->tcon;
236 6 : struct smbd_server_connection *sconn = conn->sconn;
237 :
238 6 : status = conn_force_tdis_recv(req);
239 6 : TALLOC_FREE(req);
240 6 : if (!NT_STATUS_IS_OK(status)) {
241 0 : DBG_ERR("conn_force_tdis_recv of share '%s' "
242 : "(wire_id=0x%08x) failed: %s\n",
243 : tcon->global->share_name,
244 : tcon->global->tcon_wire_id,
245 : nt_errstr(status));
246 0 : return;
247 : }
248 :
249 6 : if (conn->sconn->using_smb2) {
250 6 : vuid = conn->vuid;
251 : }
252 :
253 6 : DBG_WARNING("Closing "
254 : "share '%s' (wire_id=0x%08x)\n",
255 : tcon->global->share_name,
256 : tcon->global->tcon_wire_id);
257 :
258 6 : conn = NULL;
259 6 : status = smbXsrv_tcon_disconnect(tcon, vuid);
260 6 : if (!NT_STATUS_IS_OK(status)) {
261 0 : DBG_ERR("smbXsrv_tcon_disconnect() of share '%s' "
262 : "(wire_id=0x%08x) failed: %s\n",
263 : tcon->global->share_name,
264 : tcon->global->tcon_wire_id,
265 : nt_errstr(status));
266 0 : return;
267 : }
268 :
269 6 : TALLOC_FREE(tcon);
270 :
271 : /*
272 : * As we've been awoken, we may have changed
273 : * uid in the meantime. Ensure we're still root.
274 : */
275 6 : change_to_root_user();
276 : /*
277 : * Use 'false' in the last parameter (test) to force
278 : * a full reload of services. Prevents
279 : * reload_services caching the fact it's
280 : * been called multiple times in a row.
281 : * See BUG: https://bugzilla.samba.org/show_bug.cgi?id=14604
282 : * for details.
283 : */
284 6 : reload_services(sconn, conn_snum_used, false);
285 : }
|