smbd: use fsp_set_fd()
[samba.git] / source3 / smbd / conn.c
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 "lib/util/bitmap.h"
26
27 /****************************************************************************
28  Return the number of open connections.
29 ****************************************************************************/
30
31 int conn_num_open(struct smbd_server_connection *sconn)
32 {
33         return sconn->num_connections;
34 }
35
36 /****************************************************************************
37  Check if a snum is in use.
38 ****************************************************************************/
39
40 bool conn_snum_used(struct smbd_server_connection *sconn,
41                     int snum)
42 {
43         struct connection_struct *conn;
44
45         for (conn=sconn->connections; conn; conn=conn->next) {
46                 if (conn->params->service == snum) {
47                         return true;
48                 }
49         }
50
51         return false;
52 }
53
54 /****************************************************************************
55  Find first available connection slot, starting from a random position.
56  The randomisation stops problems with the server dieing and clients
57  thinking the server is still available.
58 ****************************************************************************/
59
60 connection_struct *conn_new(struct smbd_server_connection *sconn)
61 {
62         connection_struct *conn = NULL;
63
64         conn = talloc_zero(NULL, connection_struct);
65         if (conn == NULL) {
66                 DBG_ERR("talloc_zero failed\n");
67                 return NULL;
68         }
69         conn->params = talloc(conn, struct share_params);
70         if (conn->params == NULL) {
71                 DBG_ERR("talloc_zero failed\n");
72                 TALLOC_FREE(conn);
73                 return NULL;
74         }
75         conn->vuid_cache = talloc_zero(conn, struct vuid_cache);
76         if (conn->vuid_cache == NULL) {
77                 DBG_ERR("talloc_zero failed\n");
78                 TALLOC_FREE(conn);
79                 return NULL;
80         }
81         conn->connectpath = talloc_strdup(conn, "");
82         if (conn->connectpath == NULL) {
83                 DBG_ERR("talloc_zero failed\n");
84                 TALLOC_FREE(conn);
85                 return NULL;
86         }
87         conn->cwd_fsp = talloc_zero(conn, struct files_struct);
88         if (conn->cwd_fsp == NULL) {
89                 DBG_ERR("talloc_zero failed\n");
90                 TALLOC_FREE(conn);
91                 return NULL;
92         }
93         conn->cwd_fsp->fsp_name = synthetic_smb_fname(conn->cwd_fsp,
94                                                       ".",
95                                                       NULL,
96                                                       NULL,
97                                                       0,
98                                                       0);
99         if (conn->cwd_fsp->fsp_name == NULL) {
100                 TALLOC_FREE(conn);
101                 return NULL;
102         }
103         conn->cwd_fsp->fh = talloc_zero(conn->cwd_fsp, struct fd_handle);
104         if (conn->cwd_fsp->fh == NULL) {
105                 DBG_ERR("talloc_zero failed\n");
106                 TALLOC_FREE(conn);
107                 return NULL;
108         }
109         conn->sconn = sconn;
110         conn->force_group_gid = (gid_t)-1;
111         fsp_set_fd(conn->cwd_fsp, -1);
112         conn->cwd_fsp->fnum = FNUM_FIELD_INVALID;
113         conn->cwd_fsp->conn = conn;
114
115         DLIST_ADD(sconn->connections, conn);
116         sconn->num_connections++;
117
118         return conn;
119 }
120
121 /****************************************************************************
122  Clear a vuid out of the connection's vuid cache
123 ****************************************************************************/
124
125 static void conn_clear_vuid_cache(connection_struct *conn, uint64_t vuid)
126 {
127         int i;
128
129         for (i=0; i<VUID_CACHE_SIZE; i++) {
130                 struct vuid_cache_entry *ent;
131
132                 ent = &conn->vuid_cache->array[i];
133
134                 if (ent->vuid == vuid) {
135                         ent->vuid = UID_FIELD_INVALID;
136                         /*
137                          * We need to keep conn->session_info around
138                          * if it's equal to ent->session_info as a SMBulogoff
139                          * is often followed by a SMBtdis (with an invalid
140                          * vuid). The debug code (or regular code in
141                          * vfs_full_audit) wants to refer to the
142                          * conn->session_info pointer to print debug
143                          * statements. Theoretically this is a bug,
144                          * as once the vuid is gone the session_info
145                          * on the conn struct isn't valid any more,
146                          * but there's enough code that assumes
147                          * conn->session_info is never null that
148                          * it's easier to hold onto the old pointer
149                          * until we get a new sessionsetupX.
150                          * As everything is hung off the
151                          * conn pointer as a talloc context we're not
152                          * leaking memory here. See bug #6315. JRA.
153                          */
154                         if (conn->session_info == ent->session_info) {
155                                 ent->session_info = NULL;
156                         } else {
157                                 TALLOC_FREE(ent->session_info);
158                         }
159                         ent->read_only = False;
160                         ent->share_access = 0;
161                 }
162         }
163 }
164
165 /****************************************************************************
166  Clear a vuid out of the validity cache, and as the 'owner' of a connection.
167
168  Called from invalidate_vuid()
169 ****************************************************************************/
170
171 void conn_clear_vuid_caches(struct smbd_server_connection *sconn, uint64_t vuid)
172 {
173         connection_struct *conn;
174
175         for (conn=sconn->connections; conn;conn=conn->next) {
176                 if (conn->vuid == vuid) {
177                         conn->vuid = UID_FIELD_INVALID;
178                 }
179                 conn_clear_vuid_cache(conn, vuid);
180         }
181 }
182
183 /****************************************************************************
184  Free a conn structure - internal part.
185 ****************************************************************************/
186
187 static void conn_free_internal(connection_struct *conn)
188 {
189         vfs_handle_struct *handle = NULL, *thandle = NULL;
190         struct trans_state *state = NULL;
191
192         /* Free vfs_connection_struct */
193         handle = conn->vfs_handles;
194         while(handle) {
195                 thandle = handle->next;
196                 DLIST_REMOVE(conn->vfs_handles, handle);
197                 if (handle->free_data)
198                         handle->free_data(&handle->data);
199                 handle = thandle;
200         }
201
202         /* Free any pending transactions stored on this conn. */
203         for (state = conn->pending_trans; state; state = state->next) {
204                 /* state->setup is a talloc child of state. */
205                 SAFE_FREE(state->param);
206                 SAFE_FREE(state->data);
207         }
208
209         free_namearray(conn->veto_list);
210         free_namearray(conn->hide_list);
211         free_namearray(conn->veto_oplock_list);
212         free_namearray(conn->aio_write_behind_list);
213
214         ZERO_STRUCTP(conn);
215         talloc_destroy(conn);
216 }
217
218 /****************************************************************************
219  Free a conn structure.
220 ****************************************************************************/
221
222 void conn_free(connection_struct *conn)
223 {
224         if (conn->sconn == NULL) {
225                 conn_free_internal(conn);
226                 return;
227         }
228
229         DLIST_REMOVE(conn->sconn->connections, conn);
230         SMB_ASSERT(conn->sconn->num_connections > 0);
231         conn->sconn->num_connections--;
232
233         conn_free_internal(conn);
234 }