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