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"
26 /* The connections bitmap is expanded in increments of BITMAP_BLOCK_SZ. The
27 * maximum size of the bitmap is the largest positive integer, but you will hit
28 * the "max connections" limit, looong before that.
31 #define BITMAP_BLOCK_SZ 128
33 /****************************************************************************
34 Init the conn structures.
35 ****************************************************************************/
37 void conn_init(struct smbd_server_connection
*sconn
)
39 sconn
->smb1
.tcons
.Connections
= NULL
;
40 sconn
->smb1
.tcons
.bmap
= bitmap_talloc(sconn
, BITMAP_BLOCK_SZ
);
43 /****************************************************************************
44 Return the number of open connections.
45 ****************************************************************************/
47 int conn_num_open(struct smbd_server_connection
*sconn
)
49 return sconn
->num_tcons_open
;
52 /****************************************************************************
53 Check if a snum is in use.
54 ****************************************************************************/
56 bool conn_snum_used(int snum
)
58 struct smbd_server_connection
*sconn
= smbd_server_conn
;
60 if (sconn
->using_smb2
) {
62 struct smbd_smb2_session
*sess
;
63 for (sess
= sconn
->smb2
.sessions
.list
; sess
; sess
= sess
->next
) {
64 struct smbd_smb2_tcon
*ptcon
;
66 for (ptcon
= sess
->tcons
.list
; ptcon
; ptcon
= ptcon
->next
) {
67 if (ptcon
->compat_conn
&&
68 ptcon
->compat_conn
->params
&&
69 (ptcon
->compat_conn
->params
->service
= snum
)) {
76 connection_struct
*conn
;
77 for (conn
=sconn
->smb1
.tcons
.Connections
;conn
;conn
=conn
->next
) {
78 if (conn
->params
->service
== snum
) {
86 /****************************************************************************
87 Find a conn given a cnum.
88 ****************************************************************************/
90 connection_struct
*conn_find(struct smbd_server_connection
*sconn
,unsigned cnum
)
92 if (sconn
->using_smb2
) {
94 struct smbd_smb2_session
*sess
;
95 for (sess
= sconn
->smb2
.sessions
.list
; sess
; sess
= sess
->next
) {
96 struct smbd_smb2_tcon
*ptcon
;
98 for (ptcon
= sess
->tcons
.list
; ptcon
; ptcon
= ptcon
->next
) {
99 if (ptcon
->compat_conn
&&
100 ptcon
->compat_conn
->cnum
== cnum
) {
101 return ptcon
->compat_conn
;
108 connection_struct
*conn
;
109 for (conn
=sconn
->smb1
.tcons
.Connections
;conn
;conn
=conn
->next
,count
++) {
110 if (conn
->cnum
== cnum
) {
112 DLIST_PROMOTE(sconn
->smb1
.tcons
.Connections
,
123 /****************************************************************************
124 Find first available connection slot, starting from a random position.
125 The randomisation stops problems with the server dieing and clients
126 thinking the server is still available.
127 ****************************************************************************/
129 connection_struct
*conn_new(struct smbd_server_connection
*sconn
)
131 connection_struct
*conn
;
135 if (sconn
->using_smb2
) {
137 if (!(conn
=TALLOC_ZERO_P(NULL
, connection_struct
)) ||
138 !(conn
->params
= TALLOC_P(conn
, struct share_params
))) {
139 DEBUG(0,("TALLOC_ZERO() failed!\n"));
149 i
= bitmap_find(sconn
->smb1
.tcons
.bmap
, find_offset
);
152 /* Expand the connections bitmap. */
153 int oldsz
= sconn
->smb1
.tcons
.bmap
->n
;
154 int newsz
= sconn
->smb1
.tcons
.bmap
->n
+
156 struct bitmap
* nbmap
;
158 if (newsz
<= oldsz
) {
160 DEBUG(0,("ERROR! Out of connection structures\n"));
164 DEBUG(4,("resizing connections bitmap from %d to %d\n",
167 nbmap
= bitmap_talloc(sconn
, newsz
);
169 DEBUG(0,("ERROR! malloc fail.\n"));
173 bitmap_copy(nbmap
, sconn
->smb1
.tcons
.bmap
);
174 TALLOC_FREE(sconn
->smb1
.tcons
.bmap
);
176 sconn
->smb1
.tcons
.bmap
= nbmap
;
177 find_offset
= oldsz
; /* Start next search in the new portion. */
182 /* The bitmap position is used below as the connection number
183 * conn->cnum). This ends up as the TID field in the SMB header,
184 * which is limited to 16 bits (we skip 0xffff which is the
188 DEBUG(0, ("Maximum connection limit reached\n"));
192 if (!(conn
=TALLOC_ZERO_P(NULL
, connection_struct
)) ||
193 !(conn
->params
= TALLOC_P(conn
, struct share_params
))) {
194 DEBUG(0,("TALLOC_ZERO() failed!\n"));
200 conn
->force_group_gid
= (gid_t
)-1;
202 bitmap_set(sconn
->smb1
.tcons
.bmap
, i
);
204 sconn
->num_tcons_open
++;
206 string_set(&conn
->connectpath
,"");
207 string_set(&conn
->origpath
,"");
209 DLIST_ADD(sconn
->smb1
.tcons
.Connections
, conn
);
214 /****************************************************************************
215 Close all conn structures.
216 Return true if any were closed.
217 ****************************************************************************/
219 bool conn_close_all(struct smbd_server_connection
*sconn
)
222 if (sconn
->using_smb2
) {
224 struct smbd_smb2_session
*sess
;
225 for (sess
= sconn
->smb2
.sessions
.list
; sess
; sess
= sess
->next
) {
226 struct smbd_smb2_tcon
*tcon
, *tc_next
;
228 for (tcon
= sess
->tcons
.list
; tcon
; tcon
= tc_next
) {
229 tc_next
= tcon
->next
;
236 connection_struct
*conn
, *next
;
238 for (conn
=sconn
->smb1
.tcons
.Connections
;conn
;conn
=next
) {
240 set_current_service(conn
, 0, True
);
241 close_cnum(conn
, conn
->vuid
);
248 /****************************************************************************
249 Update last used timestamps.
250 ****************************************************************************/
252 static void conn_lastused_update(struct smbd_server_connection
*sconn
,time_t t
)
254 if (sconn
->using_smb2
) {
256 struct smbd_smb2_session
*sess
;
257 for (sess
= sconn
->smb2
.sessions
.list
; sess
; sess
= sess
->next
) {
258 struct smbd_smb2_tcon
*ptcon
;
260 for (ptcon
= sess
->tcons
.list
; ptcon
; ptcon
= ptcon
->next
) {
261 connection_struct
*conn
= ptcon
->compat_conn
;
262 /* Update if connection wasn't idle. */
263 if (conn
&& conn
->lastused
!= conn
->lastused_count
) {
265 conn
->lastused_count
= t
;
271 connection_struct
*conn
;
272 for (conn
=sconn
->smb1
.tcons
.Connections
;conn
;conn
=conn
->next
) {
273 /* Update if connection wasn't idle. */
274 if (conn
->lastused
!= conn
->lastused_count
) {
276 conn
->lastused_count
= t
;
282 /****************************************************************************
283 Idle inactive connections.
284 ****************************************************************************/
286 bool conn_idle_all(struct smbd_server_connection
*sconn
, time_t t
)
288 int deadtime
= lp_deadtime()*60;
290 conn_lastused_update(sconn
, t
);
293 deadtime
= DEFAULT_SMBD_TIMEOUT
;
296 if (sconn
->using_smb2
) {
298 struct smbd_smb2_session
*sess
;
299 for (sess
= sconn
->smb2
.sessions
.list
; sess
; sess
= sess
->next
) {
300 struct smbd_smb2_tcon
*ptcon
;
302 for (ptcon
= sess
->tcons
.list
; ptcon
; ptcon
= ptcon
->next
) {
304 connection_struct
*conn
= ptcon
->compat_conn
;
310 age
= t
- conn
->lastused
;
311 /* close dirptrs on connections that are idle */
312 if (age
> DPTR_IDLE_TIMEOUT
) {
316 if (conn
->num_files_open
> 0 || age
< deadtime
) {
323 connection_struct
*conn
;
324 for (conn
=sconn
->smb1
.tcons
.Connections
;conn
;conn
=conn
->next
) {
325 time_t age
= t
- conn
->lastused
;
327 /* close dirptrs on connections that are idle */
328 if (age
> DPTR_IDLE_TIMEOUT
) {
332 if (conn
->num_files_open
> 0 || age
< deadtime
) {
339 * Check all pipes for any open handles. We cannot
340 * idle with a handle open.
342 if (check_open_pipes()) {
349 /****************************************************************************
350 Clear a vuid out of the validity cache, and as the 'owner' of a connection.
351 ****************************************************************************/
353 void conn_clear_vuid_caches(struct smbd_server_connection
*sconn
,uint16_t vuid
)
355 connection_struct
*conn
;
357 if (sconn
->using_smb2
) {
359 struct smbd_smb2_session
*sess
;
360 for (sess
= sconn
->smb2
.sessions
.list
; sess
; sess
= sess
->next
) {
361 struct smbd_smb2_tcon
*ptcon
;
363 for (ptcon
= sess
->tcons
.list
; ptcon
; ptcon
= ptcon
->next
) {
364 if (ptcon
->compat_conn
) {
365 if (ptcon
->compat_conn
->vuid
== vuid
) {
366 ptcon
->compat_conn
->vuid
= UID_FIELD_INVALID
;
368 conn_clear_vuid_cache(ptcon
->compat_conn
, vuid
);
374 for (conn
=sconn
->smb1
.tcons
.Connections
;conn
;conn
=conn
->next
) {
375 if (conn
->vuid
== vuid
) {
376 conn
->vuid
= UID_FIELD_INVALID
;
378 conn_clear_vuid_cache(conn
, vuid
);
383 /****************************************************************************
384 Free a conn structure - internal part.
385 ****************************************************************************/
387 static void conn_free_internal(connection_struct
*conn
)
389 vfs_handle_struct
*handle
= NULL
, *thandle
= NULL
;
390 struct trans_state
*state
= NULL
;
392 /* Free vfs_connection_struct */
393 handle
= conn
->vfs_handles
;
395 thandle
= handle
->next
;
396 DLIST_REMOVE(conn
->vfs_handles
, handle
);
397 if (handle
->free_data
)
398 handle
->free_data(&handle
->data
);
402 /* Free any pending transactions stored on this conn. */
403 for (state
= conn
->pending_trans
; state
; state
= state
->next
) {
404 /* state->setup is a talloc child of state. */
405 SAFE_FREE(state
->param
);
406 SAFE_FREE(state
->data
);
409 free_namearray(conn
->veto_list
);
410 free_namearray(conn
->hide_list
);
411 free_namearray(conn
->veto_oplock_list
);
412 free_namearray(conn
->aio_write_behind_list
);
414 string_free(&conn
->connectpath
);
415 string_free(&conn
->origpath
);
418 talloc_destroy(conn
);
421 /****************************************************************************
422 Free a conn structure.
423 ****************************************************************************/
425 void conn_free(connection_struct
*conn
)
427 if (conn
->sconn
== NULL
) {
428 conn_free_internal(conn
);
432 if (conn
->sconn
->using_smb2
) {
434 conn_free_internal(conn
);
439 DLIST_REMOVE(conn
->sconn
->smb1
.tcons
.Connections
, conn
);
441 if (conn
->sconn
->smb1
.tcons
.bmap
!= NULL
) {
443 * Can be NULL for fake connections created by
444 * create_conn_struct()
446 bitmap_clear(conn
->sconn
->smb1
.tcons
.bmap
, conn
->cnum
);
449 SMB_ASSERT(conn
->sconn
->num_tcons_open
> 0);
450 conn
->sconn
->num_tcons_open
--;
452 conn_free_internal(conn
);
455 /****************************************************************************
456 Receive a smbcontrol message to forcibly unmount a share.
457 The message contains just a share name and all instances of that
459 The special sharename '*' forces unmount of all shares.
460 ****************************************************************************/
462 void msg_force_tdis(struct messaging_context
*msg
,
465 struct server_id server_id
,
468 struct smbd_server_connection
*sconn
;
469 connection_struct
*conn
, *next
;
472 sconn
= msg_ctx_to_sconn(msg
);
474 DEBUG(1, ("could not find sconn\n"));
478 fstrcpy(sharename
, (const char *)data
->data
);
480 if (strcmp(sharename
, "*") == 0) {
481 DEBUG(1,("Forcing close of all shares\n"));
482 conn_close_all(sconn
);
486 if (sconn
->using_smb2
) {
488 struct smbd_smb2_session
*sess
;
489 for (sess
= sconn
->smb2
.sessions
.list
; sess
; sess
= sess
->next
) {
490 struct smbd_smb2_tcon
*tcon
, *tc_next
;
492 for (tcon
= sess
->tcons
.list
; tcon
; tcon
= tc_next
) {
493 tc_next
= tcon
->next
;
494 if (tcon
->compat_conn
&&
495 strequal(lp_servicename(SNUM(tcon
->compat_conn
)),
497 DEBUG(1,("Forcing close of share %s cnum=%d\n",
498 sharename
, tcon
->compat_conn
->cnum
));
505 for (conn
=sconn
->smb1
.tcons
.Connections
;conn
;conn
=next
) {
507 if (strequal(lp_servicename(SNUM(conn
)), sharename
)) {
508 DEBUG(1,("Forcing close of share %s cnum=%d\n",
509 sharename
, conn
->cnum
));
510 close_cnum(conn
, (uint16
)-1);