s3:count_current_connections: do not clear orphaned entries from connections.tdb
[samba.git] / source3 / smbd / connection.c
1 /* 
2    Unix SMB/CIFS implementation.
3    connection claim routines
4    Copyright (C) Andrew Tridgell 1998
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "includes.h"
21 #include "smbd/smbd.h"
22 #include "smbd/globals.h"
23 #include "dbwrap/dbwrap.h"
24 #include "auth.h"
25 #include "../lib/tsocket/tsocket.h"
26 #include "messages.h"
27 #include "lib/conn_tdb.h"
28
29 /****************************************************************************
30  Delete a connection record.
31 ****************************************************************************/
32
33 bool yield_connection(connection_struct *conn, const char *name)
34 {
35         struct db_record *rec;
36         NTSTATUS status;
37
38         DEBUG(3,("Yielding connection to %s\n",name));
39
40         rec = connections_fetch_entry(talloc_tos(), conn, name);
41         if (rec == NULL) {
42                 DEBUG(0, ("connections_fetch_entry failed\n"));
43                 return False;
44         }
45
46         status = dbwrap_record_delete(rec);
47         if (!NT_STATUS_IS_OK(status)) {
48                 DEBUG( NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND) ? 3 : 0,
49                        ("deleting connection record returned %s\n",
50                         nt_errstr(status)));
51         }
52
53         TALLOC_FREE(rec);
54         return NT_STATUS_IS_OK(status);
55 }
56
57 struct count_stat {
58         int curr_connections;
59         const char *name;
60         bool verify;
61 };
62
63 /****************************************************************************
64  Count the entries belonging to a service in the connection db.
65 ****************************************************************************/
66
67 static int count_fn(const struct connections_key *ckey,
68                     const struct connections_data *crec,
69                     void *udp)
70 {
71         struct count_stat *cs = (struct count_stat *)udp;
72
73         if (crec->cnum == TID_FIELD_INVALID) {
74                 return 0;
75         }
76
77         if (cs->verify && !process_exists(crec->pid)) {
78                 return 0;
79         }
80
81         if (strequal(crec->servicename, cs->name)) {
82                 cs->curr_connections++;
83         }
84
85         return 0;
86 }
87
88 /****************************************************************************
89  Claim an entry in the connections database.
90 ****************************************************************************/
91
92 int count_current_connections(const char *sharename, bool verify)
93 {
94         struct count_stat cs;
95         int ret;
96
97         cs.curr_connections = 0;
98         cs.name = sharename;
99         cs.verify = verify;
100
101         /*
102          * This has a race condition, but locking the chain before hand is worse
103          * as it leads to deadlock.
104          */
105
106         /*
107          * become_root() because we might have to open connections.tdb
108          * via ctdb, which is not possible without root.
109          */
110         become_root();
111         ret = connections_forall_read(count_fn, &cs);
112         unbecome_root();
113
114         if (ret < 0) {
115                 DEBUG(0,("count_current_connections: traverse of "
116                          "connections.tdb failed\n"));
117                 return 0;
118         }
119
120         return cs.curr_connections;
121 }
122
123 bool connections_snum_used(struct smbd_server_connection *unused, int snum)
124 {
125         int active;
126
127         active = count_current_connections(lp_servicename(talloc_tos(), snum),
128                                            true);
129         if (active > 0) {
130                 return true;
131         }
132
133         return false;
134 }
135
136 /****************************************************************************
137  Claim an entry in the connections database.
138 ****************************************************************************/
139
140 bool claim_connection(connection_struct *conn, const char *name)
141 {
142         struct db_record *rec;
143         struct connections_data crec;
144         char *raddr;
145         TDB_DATA dbuf;
146         NTSTATUS status;
147
148         DEBUG(5,("claiming [%s]\n", name));
149
150         if (!(rec = connections_fetch_entry(talloc_tos(), conn, name))) {
151                 DEBUG(0, ("connections_fetch_entry failed\n"));
152                 return False;
153         }
154
155         /* Make clear that we require the optional unix_token in the source3 code */
156         SMB_ASSERT(conn->session_info->unix_token);
157
158         /* fill in the crec */
159         ZERO_STRUCT(crec);
160         crec.magic = 0x280267;
161         crec.pid = messaging_server_id(conn->sconn->msg_ctx);
162         crec.cnum = conn->cnum;
163         crec.uid = conn->session_info->unix_token->uid;
164         crec.gid = conn->session_info->unix_token->gid;
165         strlcpy(crec.servicename, lp_servicename(rec, SNUM(conn)),
166                 sizeof(crec.servicename));
167         crec.start = time(NULL);
168
169         raddr = tsocket_address_inet_addr_string(conn->sconn->remote_address,
170                                                  rec);
171         if (raddr == NULL) {
172                 return false;
173         }
174
175         strlcpy(crec.machine,get_remote_machine_name(),sizeof(crec.machine));
176         strlcpy(crec.addr, raddr, sizeof(crec.addr));
177
178         dbuf.dptr = (uint8 *)&crec;
179         dbuf.dsize = sizeof(crec);
180
181         status = dbwrap_record_store(rec, dbuf, TDB_REPLACE);
182
183         TALLOC_FREE(rec);
184
185         if (!NT_STATUS_IS_OK(status)) {
186                 DEBUG(0,("claim_connection: tdb_store failed with error %s.\n",
187                          nt_errstr(status)));
188                 return False;
189         }
190
191         return True;
192 }