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
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.
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.
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/>.
23 #include "smbd/smbd.h"
24 #include "smbd/globals.h"
25 #include "rpc_server/rpc_pipes.h"
26 #include "lib/util/tevent_ntstatus.h"
28 /****************************************************************************
29 Update last used timestamps.
30 ****************************************************************************/
32 static void conn_lastused_update(struct smbd_server_connection
*sconn
,time_t t
)
34 struct connection_struct
*conn
;
36 for (conn
=sconn
->connections
; conn
; conn
=conn
->next
) {
37 /* Update if connection wasn't idle. */
38 if (conn
->lastused
!= conn
->lastused_count
) {
40 conn
->lastused_count
= t
;
45 /****************************************************************************
46 Idle inactive connections.
47 ****************************************************************************/
49 bool conn_idle_all(struct smbd_server_connection
*sconn
, time_t t
)
51 int deadtime
= lp_deadtime()*60;
52 struct connection_struct
*conn
;
54 conn_lastused_update(sconn
, t
);
60 for (conn
=sconn
->connections
;conn
;conn
=conn
->next
) {
61 time_t age
= t
- conn
->lastused
;
63 if (conn
->num_files_open
> 0 || age
< deadtime
) {
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 ****************************************************************************/
77 static struct tevent_req
*conn_force_tdis_send(connection_struct
*conn
);
78 static void conn_force_tdis_done(struct tevent_req
*req
);
81 struct smbd_server_connection
*sconn
,
82 bool (*check_fn
)(struct connection_struct
*conn
,
86 connection_struct
*conn
;
89 for (conn
= sconn
->connections
; conn
; conn
= conn
->next
) {
90 struct smbXsrv_tcon
*tcon
;
91 bool do_close
= false;
92 struct tevent_req
*req
;
94 if (conn
->tcon
== NULL
) {
99 if (!NT_STATUS_IS_OK(tcon
->status
)) {
100 /* In the process of already being disconnected. */
104 do_close
= check_fn(conn
, private_data
);
109 req
= conn_force_tdis_send(conn
);
111 DBG_WARNING("talloc_fail forcing async close of "
113 tcon
->global
->share_name
);
117 DBG_WARNING("Forcing close of "
118 "share '%s' (wire_id=0x%08x)\n",
119 tcon
->global
->share_name
,
120 tcon
->global
->tcon_wire_id
);
122 tevent_req_set_callback(req
, conn_force_tdis_done
, conn
);
126 struct conn_force_tdis_state
{
127 struct tevent_queue
*wait_queue
;
130 static void conn_force_tdis_wait_done(struct tevent_req
*subreq
);
132 static struct tevent_req
*conn_force_tdis_send(connection_struct
*conn
)
134 struct tevent_req
*req
;
135 struct conn_force_tdis_state
*state
;
136 struct tevent_req
*subreq
;
139 /* Create this off the NULL context. We must clean up on return. */
140 req
= tevent_req_create(NULL
, &state
,
141 struct conn_force_tdis_state
);
145 state
->wait_queue
= tevent_queue_create(state
,
146 "conn_force_tdis_wait_queue");
147 if (tevent_req_nomem(state
->wait_queue
, req
)) {
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.
157 conn
->tcon
->status
= NT_STATUS_NETWORK_NAME_DELETED
;
159 for (fsp
= conn
->sconn
->files
; fsp
; fsp
= fsp
->next
) {
160 if (fsp
->conn
!= conn
) {
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.
169 fsp
->fsp_flags
.closing
= true;
171 if (fsp
->num_aio_requests
> 0) {
173 * Now wait until all aio requests on this fsp are
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.
180 subreq
= tevent_queue_wait_send(fsp
->aio_requests
,
183 if (tevent_req_nomem(subreq
, req
)) {
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.
194 subreq
= tevent_queue_wait_send(state
,
197 if (tevent_req_nomem(subreq
, req
)) {
202 tevent_req_set_callback(subreq
, conn_force_tdis_wait_done
, req
);
206 static void conn_force_tdis_wait_done(struct tevent_req
*subreq
)
208 struct tevent_req
*req
= tevent_req_callback_data(
209 subreq
, struct tevent_req
);
211 tevent_queue_wait_recv(subreq
);
213 tevent_req_done(req
);
216 static NTSTATUS
conn_force_tdis_recv(struct tevent_req
*req
)
218 return tevent_req_simple_recv_ntstatus(req
);
221 static void conn_force_tdis_done(struct tevent_req
*req
)
223 connection_struct
*conn
= tevent_req_callback_data(
224 req
, connection_struct
);
226 uint64_t vuid
= UID_FIELD_INVALID
;
227 struct smbXsrv_tcon
*tcon
= conn
->tcon
;
228 struct smbd_server_connection
*sconn
= conn
->sconn
;
230 status
= conn_force_tdis_recv(req
);
232 if (!NT_STATUS_IS_OK(status
)) {
233 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
,
241 if (conn_using_smb2(conn
->sconn
)) {
245 DBG_WARNING("Closing "
246 "share '%s' (wire_id=0x%08x)\n",
247 tcon
->global
->share_name
,
248 tcon
->global
->tcon_wire_id
);
251 status
= smbXsrv_tcon_disconnect(tcon
, vuid
);
252 if (!NT_STATUS_IS_OK(status
)) {
253 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
,
264 * As we've been awoken, we may have changed
265 * uid in the meantime. Ensure we're still root.
267 change_to_root_user();
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
276 reload_services(sconn
, conn_snum_used
, false);