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
) {
69 * Check all pipes for any open handles. We cannot
70 * idle with a handle open.
72 if (check_open_pipes()) {
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 ****************************************************************************/
85 static struct tevent_req
*conn_force_tdis_send(connection_struct
*conn
);
86 static void conn_force_tdis_done(struct tevent_req
*req
);
89 struct smbd_server_connection
*sconn
,
90 bool (*check_fn
)(struct connection_struct
*conn
,
94 connection_struct
*conn
;
97 for (conn
= sconn
->connections
; conn
; conn
= conn
->next
) {
98 struct smbXsrv_tcon
*tcon
;
99 bool do_close
= false;
100 struct tevent_req
*req
;
102 if (conn
->tcon
== NULL
) {
107 if (!NT_STATUS_IS_OK(tcon
->status
)) {
108 /* In the process of already being disconnected. */
112 do_close
= check_fn(conn
, private_data
);
117 req
= conn_force_tdis_send(conn
);
119 DBG_WARNING("talloc_fail forcing async close of "
121 tcon
->global
->share_name
);
125 DBG_WARNING("Forcing close of "
126 "share '%s' (wire_id=0x%08x)\n",
127 tcon
->global
->share_name
,
128 tcon
->global
->tcon_wire_id
);
130 tevent_req_set_callback(req
, conn_force_tdis_done
, conn
);
134 struct conn_force_tdis_state
{
135 struct tevent_queue
*wait_queue
;
138 static void conn_force_tdis_wait_done(struct tevent_req
*subreq
);
140 static struct tevent_req
*conn_force_tdis_send(connection_struct
*conn
)
142 struct tevent_req
*req
;
143 struct conn_force_tdis_state
*state
;
144 struct tevent_req
*subreq
;
147 /* Create this off the NULL context. We must clean up on return. */
148 req
= tevent_req_create(NULL
, &state
,
149 struct conn_force_tdis_state
);
153 state
->wait_queue
= tevent_queue_create(state
,
154 "conn_force_tdis_wait_queue");
155 if (tevent_req_nomem(state
->wait_queue
, req
)) {
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.
165 conn
->tcon
->status
= NT_STATUS_NETWORK_NAME_DELETED
;
167 for (fsp
= conn
->sconn
->files
; fsp
; fsp
= fsp
->next
) {
168 if (fsp
->conn
!= conn
) {
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.
177 fsp
->fsp_flags
.closing
= true;
179 if (fsp
->num_aio_requests
> 0) {
181 * Now wait until all aio requests on this fsp are
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.
188 subreq
= tevent_queue_wait_send(fsp
->aio_requests
,
191 if (tevent_req_nomem(subreq
, req
)) {
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.
202 subreq
= tevent_queue_wait_send(state
,
205 if (tevent_req_nomem(subreq
, req
)) {
210 tevent_req_set_callback(subreq
, conn_force_tdis_wait_done
, req
);
214 static void conn_force_tdis_wait_done(struct tevent_req
*subreq
)
216 struct tevent_req
*req
= tevent_req_callback_data(
217 subreq
, struct tevent_req
);
219 tevent_queue_wait_recv(subreq
);
221 tevent_req_done(req
);
224 static NTSTATUS
conn_force_tdis_recv(struct tevent_req
*req
)
226 return tevent_req_simple_recv_ntstatus(req
);
229 static void conn_force_tdis_done(struct tevent_req
*req
)
231 connection_struct
*conn
= tevent_req_callback_data(
232 req
, connection_struct
);
234 uint64_t vuid
= UID_FIELD_INVALID
;
235 struct smbXsrv_tcon
*tcon
= conn
->tcon
;
236 struct smbd_server_connection
*sconn
= conn
->sconn
;
238 status
= conn_force_tdis_recv(req
);
240 if (!NT_STATUS_IS_OK(status
)) {
241 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
,
249 if (conn
->sconn
->using_smb2
) {
253 DBG_WARNING("Closing "
254 "share '%s' (wire_id=0x%08x)\n",
255 tcon
->global
->share_name
,
256 tcon
->global
->tcon_wire_id
);
259 status
= smbXsrv_tcon_disconnect(tcon
, vuid
);
260 if (!NT_STATUS_IS_OK(status
)) {
261 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
,
272 * As we've been awoken, we may have changed
273 * uid in the meantime. Ensure we're still root.
275 change_to_root_user();
276 reload_services(sconn
, conn_snum_used
, true);