| 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 | 
 | 
|---|
| 22 | /****************************************************************************
 | 
|---|
| 23 |  Delete a connection record.
 | 
|---|
| 24 | ****************************************************************************/
 | 
|---|
| 25 | 
 | 
|---|
| 26 | bool yield_connection(connection_struct *conn, const char *name)
 | 
|---|
| 27 | {
 | 
|---|
| 28 |         struct db_record *rec;
 | 
|---|
| 29 |         NTSTATUS status;
 | 
|---|
| 30 | 
 | 
|---|
| 31 |         DEBUG(3,("Yielding connection to %s\n",name));
 | 
|---|
| 32 | 
 | 
|---|
| 33 |         if (!(rec = connections_fetch_entry(NULL, conn, name))) {
 | 
|---|
| 34 |                 DEBUG(0, ("connections_fetch_entry failed\n"));
 | 
|---|
| 35 |                 return False;
 | 
|---|
| 36 |         }
 | 
|---|
| 37 | 
 | 
|---|
| 38 |         status = rec->delete_rec(rec);
 | 
|---|
| 39 |         if (!NT_STATUS_IS_OK(status)) {
 | 
|---|
| 40 |                 DEBUG( NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND) ? 3 : 0,
 | 
|---|
| 41 |                        ("deleting connection record returned %s\n",
 | 
|---|
| 42 |                         nt_errstr(status)));
 | 
|---|
| 43 |         }
 | 
|---|
| 44 | 
 | 
|---|
| 45 |         TALLOC_FREE(rec);
 | 
|---|
| 46 |         return NT_STATUS_IS_OK(status);
 | 
|---|
| 47 | }
 | 
|---|
| 48 | 
 | 
|---|
| 49 | struct count_stat {
 | 
|---|
| 50 |         pid_t mypid;
 | 
|---|
| 51 |         int curr_connections;
 | 
|---|
| 52 |         const char *name;
 | 
|---|
| 53 |         bool Clear;
 | 
|---|
| 54 | };
 | 
|---|
| 55 | 
 | 
|---|
| 56 | /****************************************************************************
 | 
|---|
| 57 |  Count the entries belonging to a service in the connection db.
 | 
|---|
| 58 | ****************************************************************************/
 | 
|---|
| 59 | 
 | 
|---|
| 60 | static int count_fn(struct db_record *rec,
 | 
|---|
| 61 |                     const struct connections_key *ckey,
 | 
|---|
| 62 |                     const struct connections_data *crec,
 | 
|---|
| 63 |                     void *udp)
 | 
|---|
| 64 | {
 | 
|---|
| 65 |         struct count_stat *cs = (struct count_stat *)udp;
 | 
|---|
| 66 | 
 | 
|---|
| 67 |         if (crec->cnum == -1) {
 | 
|---|
| 68 |                 return 0;
 | 
|---|
| 69 |         }
 | 
|---|
| 70 | 
 | 
|---|
| 71 |         /* If the pid was not found delete the entry from connections.tdb */
 | 
|---|
| 72 | 
 | 
|---|
| 73 |         if (cs->Clear && !process_exists(crec->pid) && (errno == ESRCH)) {
 | 
|---|
| 74 |                 NTSTATUS status;
 | 
|---|
| 75 |                 DEBUG(2,("pid %s doesn't exist - deleting connections %d [%s]\n",
 | 
|---|
| 76 |                          procid_str_static(&crec->pid), crec->cnum,
 | 
|---|
| 77 |                          crec->servicename));
 | 
|---|
| 78 | 
 | 
|---|
| 79 |                 status = rec->delete_rec(rec);
 | 
|---|
| 80 |                 if (!NT_STATUS_IS_OK(status)) {
 | 
|---|
| 81 |                         DEBUG(0,("count_fn: tdb_delete failed with error %s\n",
 | 
|---|
| 82 |                                  nt_errstr(status)));
 | 
|---|
| 83 |                 }
 | 
|---|
| 84 |                 return 0;
 | 
|---|
| 85 |         }
 | 
|---|
| 86 | 
 | 
|---|
| 87 |         if (strequal(crec->servicename, cs->name))
 | 
|---|
| 88 |                 cs->curr_connections++;
 | 
|---|
| 89 | 
 | 
|---|
| 90 |         return 0;
 | 
|---|
| 91 | }
 | 
|---|
| 92 | 
 | 
|---|
| 93 | /****************************************************************************
 | 
|---|
| 94 |  Claim an entry in the connections database.
 | 
|---|
| 95 | ****************************************************************************/
 | 
|---|
| 96 | 
 | 
|---|
| 97 | int count_current_connections( const char *sharename, bool clear  )
 | 
|---|
| 98 | {
 | 
|---|
| 99 |         struct count_stat cs;
 | 
|---|
| 100 | 
 | 
|---|
| 101 |         cs.mypid = sys_getpid();
 | 
|---|
| 102 |         cs.curr_connections = 0;
 | 
|---|
| 103 |         cs.name = sharename;
 | 
|---|
| 104 |         cs.Clear = clear;
 | 
|---|
| 105 | 
 | 
|---|
| 106 |         /*
 | 
|---|
| 107 |          * This has a race condition, but locking the chain before hand is worse
 | 
|---|
| 108 |          * as it leads to deadlock.
 | 
|---|
| 109 |          */
 | 
|---|
| 110 | 
 | 
|---|
| 111 |         if (connections_forall(count_fn, &cs) == -1) {
 | 
|---|
| 112 |                 DEBUG(0,("count_current_connections: traverse of "
 | 
|---|
| 113 |                          "connections.tdb failed\n"));
 | 
|---|
| 114 |                 return False;
 | 
|---|
| 115 |         }
 | 
|---|
| 116 | 
 | 
|---|
| 117 |         return cs.curr_connections;
 | 
|---|
| 118 | }
 | 
|---|
| 119 | 
 | 
|---|
| 120 | /****************************************************************************
 | 
|---|
| 121 |  Count the number of connections open across all shares.
 | 
|---|
| 122 | ****************************************************************************/
 | 
|---|
| 123 | 
 | 
|---|
| 124 | int count_all_current_connections(void)
 | 
|---|
| 125 | {
 | 
|---|
| 126 |         return count_current_connections(NULL, True /* clear stale entries */);
 | 
|---|
| 127 | }
 | 
|---|
| 128 | 
 | 
|---|
| 129 | /****************************************************************************
 | 
|---|
| 130 |  Claim an entry in the connections database.
 | 
|---|
| 131 | ****************************************************************************/
 | 
|---|
| 132 | 
 | 
|---|
| 133 | bool claim_connection(connection_struct *conn, const char *name,
 | 
|---|
| 134 |                       uint32 msg_flags)
 | 
|---|
| 135 | {
 | 
|---|
| 136 |         struct db_record *rec;
 | 
|---|
| 137 |         struct connections_data crec;
 | 
|---|
| 138 |         TDB_DATA dbuf;
 | 
|---|
| 139 |         NTSTATUS status;
 | 
|---|
| 140 |         char addr[INET6_ADDRSTRLEN];
 | 
|---|
| 141 | 
 | 
|---|
| 142 |         DEBUG(5,("claiming [%s]\n", name));
 | 
|---|
| 143 | 
 | 
|---|
| 144 |         if (!(rec = connections_fetch_entry(talloc_tos(), conn, name))) {
 | 
|---|
| 145 |                 DEBUG(0, ("connections_fetch_entry failed\n"));
 | 
|---|
| 146 |                 return False;
 | 
|---|
| 147 |         }
 | 
|---|
| 148 | 
 | 
|---|
| 149 |         /* fill in the crec */
 | 
|---|
| 150 |         ZERO_STRUCT(crec);
 | 
|---|
| 151 |         crec.magic = 0x280267;
 | 
|---|
| 152 |         crec.pid = procid_self();
 | 
|---|
| 153 |         crec.cnum = conn?conn->cnum:-1;
 | 
|---|
| 154 |         if (conn) {
 | 
|---|
| 155 |                 crec.uid = conn->server_info->utok.uid;
 | 
|---|
| 156 |                 crec.gid = conn->server_info->utok.gid;
 | 
|---|
| 157 |                 strlcpy(crec.servicename, lp_servicename(SNUM(conn)),
 | 
|---|
| 158 |                         sizeof(crec.servicename));
 | 
|---|
| 159 |         }
 | 
|---|
| 160 |         crec.start = time(NULL);
 | 
|---|
| 161 |         crec.bcast_msg_flags = msg_flags;
 | 
|---|
| 162 | 
 | 
|---|
| 163 |         strlcpy(crec.machine,get_remote_machine_name(),sizeof(crec.machine));
 | 
|---|
| 164 |         strlcpy(crec.addr,conn?conn->client_address:
 | 
|---|
| 165 |                         client_addr(get_client_fd(),addr,sizeof(addr)),
 | 
|---|
| 166 |                 sizeof(crec.addr));
 | 
|---|
| 167 | 
 | 
|---|
| 168 |         dbuf.dptr = (uint8 *)&crec;
 | 
|---|
| 169 |         dbuf.dsize = sizeof(crec);
 | 
|---|
| 170 | 
 | 
|---|
| 171 |         status = rec->store(rec, dbuf, TDB_REPLACE);
 | 
|---|
| 172 | 
 | 
|---|
| 173 |         TALLOC_FREE(rec);
 | 
|---|
| 174 | 
 | 
|---|
| 175 |         if (!NT_STATUS_IS_OK(status)) {
 | 
|---|
| 176 |                 DEBUG(0,("claim_connection: tdb_store failed with error %s.\n",
 | 
|---|
| 177 |                          nt_errstr(status)));
 | 
|---|
| 178 |                 return False;
 | 
|---|
| 179 |         }
 | 
|---|
| 180 | 
 | 
|---|
| 181 |         return True;
 | 
|---|
| 182 | }
 | 
|---|
| 183 | 
 | 
|---|
| 184 | bool register_message_flags(bool doreg, uint32 msg_flags)
 | 
|---|
| 185 | {
 | 
|---|
| 186 |         struct db_record *rec;
 | 
|---|
| 187 |         struct connections_data *pcrec;
 | 
|---|
| 188 |         NTSTATUS status;
 | 
|---|
| 189 | 
 | 
|---|
| 190 |         DEBUG(10,("register_message_flags: %s flags 0x%x\n",
 | 
|---|
| 191 |                 doreg ? "adding" : "removing",
 | 
|---|
| 192 |                 (unsigned int)msg_flags ));
 | 
|---|
| 193 | 
 | 
|---|
| 194 |         if (!(rec = connections_fetch_entry(NULL, NULL, ""))) {
 | 
|---|
| 195 |                 DEBUG(0, ("connections_fetch_entry failed\n"));
 | 
|---|
| 196 |                 return False;
 | 
|---|
| 197 |         }
 | 
|---|
| 198 | 
 | 
|---|
| 199 |         if (rec->value.dsize != sizeof(struct connections_data)) {
 | 
|---|
| 200 |                 DEBUG(0,("register_message_flags: Got wrong record size\n"));
 | 
|---|
| 201 |                 TALLOC_FREE(rec);
 | 
|---|
| 202 |                 return False;
 | 
|---|
| 203 |         }
 | 
|---|
| 204 | 
 | 
|---|
| 205 |         pcrec = (struct connections_data *)rec->value.dptr;
 | 
|---|
| 206 |         if (doreg)
 | 
|---|
| 207 |                 pcrec->bcast_msg_flags |= msg_flags;
 | 
|---|
| 208 |         else
 | 
|---|
| 209 |                 pcrec->bcast_msg_flags &= ~msg_flags;
 | 
|---|
| 210 | 
 | 
|---|
| 211 |         status = rec->store(rec, rec->value, TDB_REPLACE);
 | 
|---|
| 212 | 
 | 
|---|
| 213 |         if (!NT_STATUS_IS_OK(status)) {
 | 
|---|
| 214 |                 DEBUG(0,("register_message_flags: tdb_store failed: %s.\n",
 | 
|---|
| 215 |                          nt_errstr(status)));
 | 
|---|
| 216 |                 TALLOC_FREE(rec);
 | 
|---|
| 217 |                 return False;
 | 
|---|
| 218 |         }
 | 
|---|
| 219 | 
 | 
|---|
| 220 |         DEBUG(10,("register_message_flags: new flags 0x%x\n",
 | 
|---|
| 221 |                 (unsigned int)pcrec->bcast_msg_flags ));
 | 
|---|
| 222 | 
 | 
|---|
| 223 |         TALLOC_FREE(rec);
 | 
|---|
| 224 | 
 | 
|---|
| 225 |         return True;
 | 
|---|
| 226 | }
 | 
|---|