1/* 2 Unix SMB/CIFS implementation. 3 Manage connections_struct structures 4 Copyright (C) Andrew Tridgell 1998 5 Copyright (C) Alexander Bokovoy 2002 6 7 This program is free software; you can redistribute it and/or modify 8 it under the terms of the GNU General Public License as published by 9 the Free Software Foundation; either version 3 of the License, or 10 (at your option) any later version. 11 12 This program is distributed in the hope that it will be useful, 13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with this program. If not, see <http://www.gnu.org/licenses/>. 19*/ 20 21#include "includes.h" 22#include "smbd/globals.h" 23 24/* The connections bitmap is expanded in increments of BITMAP_BLOCK_SZ. The 25 * maximum size of the bitmap is the largest positive integer, but you will hit 26 * the "max connections" limit, looong before that. 27 */ 28#define BITMAP_BLOCK_SZ 128 29 30/**************************************************************************** 31init the conn structures 32****************************************************************************/ 33void conn_init(struct smbd_server_connection *sconn) 34{ 35 sconn->smb1.tcons.Connections = NULL; 36 sconn->smb1.tcons.num_open = 0; 37 sconn->smb1.tcons.bmap = bitmap_allocate(BITMAP_BLOCK_SZ); 38} 39 40/**************************************************************************** 41return the number of open connections 42****************************************************************************/ 43int conn_num_open(struct smbd_server_connection *sconn) 44{ 45 return sconn->smb1.tcons.num_open; 46} 47 48 49/**************************************************************************** 50check if a snum is in use 51****************************************************************************/ 52bool conn_snum_used(int snum) 53{ 54 struct smbd_server_connection *sconn = smbd_server_conn; 55 connection_struct *conn; 56 for (conn=sconn->smb1.tcons.Connections;conn;conn=conn->next) { 57 if (conn->params->service == snum) { 58 return(True); 59 } 60 } 61 return(False); 62} 63 64/**************************************************************************** 65 Find a conn given a cnum. 66****************************************************************************/ 67 68connection_struct *conn_find(struct smbd_server_connection *sconn,unsigned cnum) 69{ 70 int count=0; 71 connection_struct *conn; 72 73 for (conn=sconn->smb1.tcons.Connections;conn;conn=conn->next,count++) { 74 if (conn->cnum == cnum) { 75 if (count > 10) { 76 DLIST_PROMOTE(sconn->smb1.tcons.Connections, 77 conn); 78 } 79 return conn; 80 } 81 } 82 83 return NULL; 84} 85 86/**************************************************************************** 87 find first available connection slot, starting from a random position. 88The randomisation stops problems with the server dieing and clients 89thinking the server is still available. 90****************************************************************************/ 91connection_struct *conn_new(struct smbd_server_connection *sconn) 92{ 93 connection_struct *conn; 94 int i; 95 int find_offset = 1; 96 97 if (sconn->allow_smb2) { 98 if (!(conn=TALLOC_ZERO_P(NULL, connection_struct)) || 99 !(conn->params = TALLOC_P(conn, struct share_params))) { 100 DEBUG(0,("TALLOC_ZERO() failed!\n")); 101 TALLOC_FREE(conn); 102 return NULL; 103 } 104 conn->sconn = sconn; 105 return conn; 106 } 107 108find_again: 109 i = bitmap_find(sconn->smb1.tcons.bmap, find_offset); 110 111 if (i == -1) { 112 /* Expand the connections bitmap. */ 113 int oldsz = sconn->smb1.tcons.bmap->n; 114 int newsz = sconn->smb1.tcons.bmap->n + 115 BITMAP_BLOCK_SZ; 116 struct bitmap * nbmap; 117 118 if (newsz <= oldsz) { 119 /* Integer wrap. */ 120 DEBUG(0,("ERROR! Out of connection structures\n")); 121 return NULL; 122 } 123 124 DEBUG(4,("resizing connections bitmap from %d to %d\n", 125 oldsz, newsz)); 126 127 nbmap = bitmap_allocate(newsz); 128 if (!nbmap) { 129 DEBUG(0,("ERROR! malloc fail.\n")); 130 return NULL; 131 } 132 133 bitmap_copy(nbmap, sconn->smb1.tcons.bmap); 134 bitmap_free(sconn->smb1.tcons.bmap); 135 136 sconn->smb1.tcons.bmap = nbmap; 137 find_offset = oldsz; /* Start next search in the new portion. */ 138 139 goto find_again; 140 } 141 142 /* The bitmap position is used below as the connection number 143 * conn->cnum). This ends up as the TID field in the SMB header, 144 * which is limited to 16 bits (we skip 0xffff which is the 145 * NULL TID). 146 */ 147 if (i > 65534) { 148 DEBUG(0, ("Maximum connection limit reached\n")); 149 return NULL; 150 } 151 152 if (!(conn=TALLOC_ZERO_P(NULL, connection_struct)) || 153 !(conn->params = TALLOC_P(conn, struct share_params))) { 154 DEBUG(0,("TALLOC_ZERO() failed!\n")); 155 TALLOC_FREE(conn); 156 return NULL; 157 } 158 conn->sconn = sconn; 159 conn->cnum = i; 160 conn->force_group_gid = (gid_t)-1; 161 162 bitmap_set(sconn->smb1.tcons.bmap, i); 163 164 sconn->smb1.tcons.num_open++; 165 166 string_set(&conn->connectpath,""); 167 string_set(&conn->origpath,""); 168 169 DLIST_ADD(sconn->smb1.tcons.Connections, conn); 170 171 return conn; 172} 173 174/**************************************************************************** 175 Close all conn structures. 176return true if any were closed 177****************************************************************************/ 178bool conn_close_all(struct smbd_server_connection *sconn) 179{ 180 connection_struct *conn, *next; 181 bool ret = false; 182 for (conn=sconn->smb1.tcons.Connections;conn;conn=next) { 183 next=conn->next; 184 set_current_service(conn, 0, True); 185 close_cnum(conn, conn->vuid); 186 ret = true; 187 } 188 return ret; 189} 190 191/**************************************************************************** 192 Idle inactive connections. 193****************************************************************************/ 194 195bool conn_idle_all(struct smbd_server_connection *sconn,time_t t) 196{ 197 int deadtime = lp_deadtime()*60; 198 pipes_struct *plist = NULL; 199 connection_struct *conn; 200 bool ret = true; 201 202 if (deadtime <= 0) 203 deadtime = DEFAULT_SMBD_TIMEOUT; 204 205 for (conn=sconn->smb1.tcons.Connections;conn;conn=conn->next) { 206 207 time_t age = t - conn->lastused; 208 209 /* Update if connection wasn't idle. */ 210 if (conn->lastused != conn->lastused_count) { 211 conn->lastused = t; 212 conn->lastused_count = t; 213 age = 0; 214 } 215 216 /* close dirptrs on connections that are idle */ 217 if (age > DPTR_IDLE_TIMEOUT) { 218 dptr_idlecnum(conn); 219 } 220 221 if (conn->num_files_open > 0 || age < deadtime) { 222 ret = false; 223 } 224 } 225 226 /* 227 * Check all pipes for any open handles. We cannot 228 * idle with a handle open. 229 */ 230 231 for (plist = get_first_internal_pipe(); plist; 232 plist = get_next_internal_pipe(plist)) { 233 if (num_pipe_handles(plist->pipe_handles) != 0) { 234 ret = false; 235 break; 236 } 237 } 238 239 return ret; 240} 241 242/**************************************************************************** 243 Clear a vuid out of the validity cache, and as the 'owner' of a connection. 244****************************************************************************/ 245 246void conn_clear_vuid_caches(struct smbd_server_connection *sconn,uint16_t vuid) 247{ 248 connection_struct *conn; 249 250 for (conn=sconn->smb1.tcons.Connections;conn;conn=conn->next) { 251 if (conn->vuid == vuid) { 252 conn->vuid = UID_FIELD_INVALID; 253 } 254 conn_clear_vuid_cache(conn, vuid); 255 } 256} 257 258/**************************************************************************** 259 Free a conn structure - internal part. 260****************************************************************************/ 261 262static void conn_free_internal(connection_struct *conn) 263{ 264 vfs_handle_struct *handle = NULL, *thandle = NULL; 265 struct trans_state *state = NULL; 266 267 /* Free vfs_connection_struct */ 268 handle = conn->vfs_handles; 269 while(handle) { 270 thandle = handle->next; 271 DLIST_REMOVE(conn->vfs_handles, handle); 272 if (handle->free_data) 273 handle->free_data(&handle->data); 274 handle = thandle; 275 } 276 277 /* Free any pending transactions stored on this conn. */ 278 for (state = conn->pending_trans; state; state = state->next) { 279 /* state->setup is a talloc child of state. */ 280 SAFE_FREE(state->param); 281 SAFE_FREE(state->data); 282 } 283 284 free_namearray(conn->veto_list); 285 free_namearray(conn->hide_list); 286 free_namearray(conn->veto_oplock_list); 287 free_namearray(conn->aio_write_behind_list); 288 289 string_free(&conn->connectpath); 290 string_free(&conn->origpath); 291 292 ZERO_STRUCTP(conn); 293 talloc_destroy(conn); 294} 295 296/**************************************************************************** 297 Free a conn structure. 298****************************************************************************/ 299 300void conn_free(connection_struct *conn) 301{ 302 if (conn->sconn == NULL) { 303 conn_free_internal(conn); 304 return; 305 } 306 307 if (conn->sconn->allow_smb2) { 308 conn_free_internal(conn); 309 return; 310 } 311 312 DLIST_REMOVE(conn->sconn->smb1.tcons.Connections, conn); 313 314 bitmap_clear(conn->sconn->smb1.tcons.bmap, conn->cnum); 315 316 SMB_ASSERT(conn->sconn->smb1.tcons.num_open > 0); 317 conn->sconn->smb1.tcons.num_open--; 318 319 conn_free_internal(conn); 320} 321 322/**************************************************************************** 323receive a smbcontrol message to forcibly unmount a share 324the message contains just a share name and all instances of that 325share are unmounted 326the special sharename '*' forces unmount of all shares 327****************************************************************************/ 328void msg_force_tdis(struct messaging_context *msg, 329 void *private_data, 330 uint32_t msg_type, 331 struct server_id server_id, 332 DATA_BLOB *data) 333{ 334 struct smbd_server_connection *sconn = smbd_server_conn; 335 connection_struct *conn, *next; 336 fstring sharename; 337 338 fstrcpy(sharename, (const char *)data->data); 339 340 if (strcmp(sharename, "*") == 0) { 341 DEBUG(1,("Forcing close of all shares\n")); 342 conn_close_all(sconn); 343 return; 344 } 345 346 for (conn=sconn->smb1.tcons.Connections;conn;conn=next) { 347 next=conn->next; 348 if (strequal(lp_servicename(SNUM(conn)), sharename)) { 349 DEBUG(1,("Forcing close of share %s cnum=%d\n", 350 sharename, conn->cnum)); 351 close_cnum(conn, (uint16)-1); 352 } 353 } 354} 355