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 2 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, write to the Free Software 18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19*/ 20 21#include "includes.h" 22 23static TDB_CONTEXT *tdb; 24 25/**************************************************************************** 26 Return the connection tdb context (used for message send all). 27****************************************************************************/ 28 29TDB_CONTEXT *conn_tdb_ctx(void) 30{ 31 if (!tdb) 32 tdb = tdb_open_log(lock_path("connections.tdb"), 0, TDB_CLEAR_IF_FIRST|TDB_DEFAULT, 33 O_RDWR | O_CREAT, 0644); 34 35 return tdb; 36} 37 38static void make_conn_key(connection_struct *conn, const char *name, TDB_DATA *pkbuf, struct connections_key *pkey) 39{ 40 ZERO_STRUCTP(pkey); 41 pkey->pid = sys_getpid(); 42 pkey->cnum = conn?conn->cnum:-1; 43 fstrcpy(pkey->name, name); 44#ifdef DEVELOPER 45 /* valgrind fixer... */ 46 { 47 size_t sl = strlen(pkey->name); 48 if (sizeof(fstring)-sl) 49 memset(&pkey->name[sl], '\0', sizeof(fstring)-sl); 50 } 51#endif 52 53 pkbuf->dptr = (char *)pkey; 54 pkbuf->dsize = sizeof(*pkey); 55} 56 57/**************************************************************************** 58 Delete a connection record. 59****************************************************************************/ 60 61BOOL yield_connection(connection_struct *conn, const char *name) 62{ 63 struct connections_key key; 64 TDB_DATA kbuf; 65 66 if (!tdb) 67 return False; 68 69 DEBUG(3,("Yielding connection to %s\n",name)); 70 71 make_conn_key(conn, name, &kbuf, &key); 72 73 if (tdb_delete(tdb, kbuf) != 0) { 74 int dbg_lvl = (!conn && (tdb_error(tdb) == TDB_ERR_NOEXIST)) ? 3 : 0; 75 DEBUG(dbg_lvl,("yield_connection: tdb_delete for name %s failed with error %s.\n", 76 name, tdb_errorstr(tdb) )); 77 return (False); 78 } 79 80 return(True); 81} 82 83struct count_stat { 84 pid_t mypid; 85 int curr_connections; 86 char *name; 87 BOOL Clear; 88}; 89 90/**************************************************************************** 91 Count the entries belonging to a service in the connection db. 92****************************************************************************/ 93 94static int count_fn( TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *udp) 95{ 96 struct connections_data crec; 97 struct count_stat *cs = (struct count_stat *)udp; 98 99 if (dbuf.dsize != sizeof(crec)) 100 return 0; 101 102 memcpy(&crec, dbuf.dptr, sizeof(crec)); 103 104 if (crec.cnum == -1) 105 return 0; 106 107 /* If the pid was not found delete the entry from connections.tdb */ 108 109 if (cs->Clear && !process_exists(crec.pid) && (errno == ESRCH)) { 110 DEBUG(2,("pid %u doesn't exist - deleting connections %d [%s]\n", 111 (unsigned int)crec.pid, crec.cnum, crec.name)); 112 if (tdb_delete(the_tdb, kbuf) != 0) 113 DEBUG(0,("count_fn: tdb_delete failed with error %s\n", tdb_errorstr(tdb) )); 114 return 0; 115 } 116 117 if (strequal(crec.name, cs->name)) 118 cs->curr_connections++; 119 120 return 0; 121} 122 123/**************************************************************************** 124 Claim an entry in the connections database. 125****************************************************************************/ 126 127BOOL claim_connection(connection_struct *conn, const char *name,int max_connections,BOOL Clear, uint32 msg_flags) 128{ 129 struct connections_key key; 130 struct connections_data crec; 131 TDB_DATA kbuf, dbuf; 132 133 if (!tdb) 134 tdb = tdb_open_log(lock_path("connections.tdb"), 0, TDB_CLEAR_IF_FIRST|TDB_DEFAULT, 135 O_RDWR | O_CREAT, 0644); 136 137 if (!tdb) 138 return False; 139 140 /* 141 * Enforce the max connections parameter. 142 */ 143 144 if (max_connections > 0) { 145 struct count_stat cs; 146 147 cs.mypid = sys_getpid(); 148 cs.curr_connections = 0; 149 cs.name = lp_servicename(SNUM(conn)); 150 cs.Clear = Clear; 151 152 /* 153 * This has a race condition, but locking the chain before hand is worse 154 * as it leads to deadlock. 155 */ 156 157 if (tdb_traverse(tdb, count_fn, &cs) == -1) { 158 DEBUG(0,("claim_connection: traverse of connections.tdb failed with error %s.\n", 159 tdb_errorstr(tdb) )); 160 return False; 161 } 162 163 if (cs.curr_connections >= max_connections) { 164 DEBUG(1,("claim_connection: Max connections (%d) exceeded for %s\n", 165 max_connections, name )); 166 return False; 167 } 168 } 169 170 DEBUG(5,("claiming %s %d\n",name,max_connections)); 171 172 make_conn_key(conn, name, &kbuf, &key); 173 174 /* fill in the crec */ 175 ZERO_STRUCT(crec); 176 crec.magic = 0x280267; 177 crec.pid = sys_getpid(); 178 crec.cnum = conn?conn->cnum:-1; 179 if (conn) { 180 crec.uid = conn->uid; 181 crec.gid = conn->gid; 182 safe_strcpy(crec.name, 183 lp_servicename(SNUM(conn)),sizeof(crec.name)-1); 184 } 185 crec.start = time(NULL); 186 crec.bcast_msg_flags = msg_flags; 187 188 safe_strcpy(crec.machine,get_remote_machine_name(),sizeof(crec.machine)-1); 189 safe_strcpy(crec.addr,conn?conn->client_address:client_addr(),sizeof(crec.addr)-1); 190 191 dbuf.dptr = (char *)&crec; 192 dbuf.dsize = sizeof(crec); 193 194 if (tdb_store(tdb, kbuf, dbuf, TDB_REPLACE) != 0) { 195 DEBUG(0,("claim_connection: tdb_store failed with error %s.\n", 196 tdb_errorstr(tdb) )); 197 return False; 198 } 199 200 return True; 201} 202 203BOOL register_message_flags(BOOL doreg, uint32 msg_flags) 204{ 205 struct connections_key key; 206 struct connections_data *pcrec; 207 TDB_DATA kbuf, dbuf; 208 209 if (!tdb) 210 return False; 211 212 DEBUG(10,("register_message_flags: %s flags 0x%x\n", 213 doreg ? "adding" : "removing", 214 (unsigned int)msg_flags )); 215 216 make_conn_key(NULL, "", &kbuf, &key); 217 218 dbuf = tdb_fetch(tdb, kbuf); 219 if (!dbuf.dptr) { 220 DEBUG(0,("register_message_flags: tdb_fetch failed\n")); 221 return False; 222 } 223 224 pcrec = (struct connections_data *)dbuf.dptr; 225 pcrec->bcast_msg_flags = msg_flags; 226 if (doreg) 227 pcrec->bcast_msg_flags |= msg_flags; 228 else 229 pcrec->bcast_msg_flags &= ~msg_flags; 230 231 if (tdb_store(tdb, kbuf, dbuf, TDB_REPLACE) != 0) { 232 DEBUG(0,("register_message_flags: tdb_store failed with error %s.\n", 233 tdb_errorstr(tdb) )); 234 SAFE_FREE(dbuf.dptr); 235 return False; 236 } 237 238 DEBUG(10,("register_message_flags: new flags 0x%x\n", 239 (unsigned int)pcrec->bcast_msg_flags )); 240 241 SAFE_FREE(dbuf.dptr); 242 return True; 243} 244