X-Git-Url: http://git.samba.org/samba.git/?p=sfrench%2Fsamba-autobuild%2F.git;a=blobdiff_plain;f=source3%2Fsmbd%2Fconnection.c;h=65b7c352c550368ed1fbeb13d9525f574706889d;hp=17b5be8a7bb0548b942bc34a7a62d2e1963f6e31;hb=e5a951325a6cac8567af3a66de6d2df577508ae4;hpb=a47d06a2c2c67cdc0b1dfc2d32df65f2b1bbeeda diff --git a/source3/smbd/connection.c b/source3/smbd/connection.c index 17b5be8a7bb..65b7c352c55 100644 --- a/source3/smbd/connection.c +++ b/source3/smbd/connection.c @@ -5,7 +5,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or + the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, @@ -14,68 +14,42 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + along with this program. If not, see . */ #include "includes.h" -static TDB_CONTEXT *tdb; - -/**************************************************************************** - Return the connection tdb context (used for message send all). -****************************************************************************/ - -TDB_CONTEXT *conn_tdb_ctx(void) -{ - if (!tdb) - tdb = tdb_open_log(lock_path("connections.tdb"), 0, TDB_CLEAR_IF_FIRST|TDB_DEFAULT, - O_RDWR | O_CREAT, 0644); - - return tdb; -} - -static void make_conn_key(connection_struct *conn, const char *name, TDB_DATA *pkbuf, struct connections_key *pkey) -{ - ZERO_STRUCTP(pkey); - pkey->pid = sys_getpid(); - pkey->cnum = conn?conn->cnum:-1; - fstrcpy(pkey->name, name); - - pkbuf->dptr = (char *)pkey; - pkbuf->dsize = sizeof(*pkey); -} - /**************************************************************************** Delete a connection record. ****************************************************************************/ BOOL yield_connection(connection_struct *conn, const char *name) { - struct connections_key key; - TDB_DATA kbuf; - - if (!tdb) - return False; + struct db_record *rec; + NTSTATUS status; DEBUG(3,("Yielding connection to %s\n",name)); - make_conn_key(conn, name, &kbuf, &key); + if (!(rec = connections_fetch_entry(NULL, conn, name))) { + DEBUG(0, ("connections_fetch_entry failed\n")); + return False; + } - if (tdb_delete(tdb, kbuf) != 0) { - int dbg_lvl = (!conn && (tdb_error(tdb) == TDB_ERR_NOEXIST)) ? 3 : 0; - DEBUG(dbg_lvl,("yield_connection: tdb_delete for name %s failed with error %s.\n", - name, tdb_errorstr(tdb) )); - return (False); + status = rec->delete_rec(rec); + if (!NT_STATUS_IS_OK(status)) { + DEBUG( NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND) ? 3 : 0, + ("deleting connection record returned %s\n", + nt_errstr(status))); } - return(True); + TALLOC_FREE(rec); + return NT_STATUS_IS_OK(status); } struct count_stat { pid_t mypid; int curr_connections; - char *name; + const char *name; BOOL Clear; }; @@ -83,30 +57,34 @@ struct count_stat { Count the entries belonging to a service in the connection db. ****************************************************************************/ -static int count_fn( TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *udp) +static int count_fn(struct db_record *rec, + const struct connections_key *ckey, + const struct connections_data *crec, + void *udp) { - struct connections_data crec; struct count_stat *cs = (struct count_stat *)udp; - if (dbuf.dsize != sizeof(crec)) - return 0; - - memcpy(&crec, dbuf.dptr, sizeof(crec)); - - if (crec.cnum == -1) + if (crec->cnum == -1) { return 0; + } /* If the pid was not found delete the entry from connections.tdb */ - if (cs->Clear && !process_exists(crec.pid) && (errno == ESRCH)) { - DEBUG(2,("pid %u doesn't exist - deleting connections %d [%s]\n", - (unsigned int)crec.pid, crec.cnum, crec.name)); - if (tdb_delete(the_tdb, kbuf) != 0) - DEBUG(0,("count_fn: tdb_delete failed with error %s\n", tdb_errorstr(tdb) )); + if (cs->Clear && !process_exists(crec->pid) && (errno == ESRCH)) { + NTSTATUS status; + DEBUG(2,("pid %s doesn't exist - deleting connections %d [%s]\n", + procid_str_static(&crec->pid), crec->cnum, + crec->servicename)); + + status = rec->delete_rec(rec); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0,("count_fn: tdb_delete failed with error %s\n", + nt_errstr(status))); + } return 0; } - if (strequal(crec.name, cs->name)) + if (strequal(crec->servicename, cs->name)) cs->curr_connections++; return 0; @@ -116,76 +94,76 @@ static int count_fn( TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *u Claim an entry in the connections database. ****************************************************************************/ -BOOL claim_connection(connection_struct *conn, const char *name,int max_connections,BOOL Clear, uint32 msg_flags) +int count_current_connections( const char *sharename, BOOL clear ) { - struct connections_key key; - struct connections_data crec; - TDB_DATA kbuf, dbuf; - - if (!tdb) - tdb = tdb_open_log(lock_path("connections.tdb"), 0, TDB_CLEAR_IF_FIRST|TDB_DEFAULT, - O_RDWR | O_CREAT, 0644); + struct count_stat cs; - if (!tdb) - return False; + cs.mypid = sys_getpid(); + cs.curr_connections = 0; + cs.name = sharename; + cs.Clear = clear; /* - * Enforce the max connections parameter. + * This has a race condition, but locking the chain before hand is worse + * as it leads to deadlock. */ - if (max_connections > 0) { - struct count_stat cs; - - cs.mypid = sys_getpid(); - cs.curr_connections = 0; - cs.name = lp_servicename(SNUM(conn)); - cs.Clear = Clear; + if (connections_forall(count_fn, &cs) == -1) { + DEBUG(0,("count_current_connections: traverse of " + "connections.tdb failed\n")); + return False; + } - /* - * This has a race condition, but locking the chain before hand is worse - * as it leads to deadlock. - */ + return cs.curr_connections; +} - if (tdb_traverse(tdb, count_fn, &cs) == -1) { - DEBUG(0,("claim_connection: traverse of connections.tdb failed with error %s.\n", - tdb_errorstr(tdb) )); - return False; - } +/**************************************************************************** + Claim an entry in the connections database. +****************************************************************************/ - if (cs.curr_connections >= max_connections) { - DEBUG(1,("claim_connection: Max connections (%d) exceeded for %s\n", - max_connections, name )); - return False; - } - } +BOOL claim_connection(connection_struct *conn, const char *name, + uint32 msg_flags) +{ + struct db_record *rec; + struct connections_data crec; + TDB_DATA dbuf; + NTSTATUS status; - DEBUG(5,("claiming %s %d\n",name,max_connections)); + DEBUG(5,("claiming [%s]\n", name)); - make_conn_key(conn, name, &kbuf, &key); + if (!(rec = connections_fetch_entry(NULL, conn, name))) { + DEBUG(0, ("connections_fetch_entry failed\n")); + return False; + } /* fill in the crec */ ZERO_STRUCT(crec); crec.magic = 0x280267; - crec.pid = sys_getpid(); + crec.pid = procid_self(); crec.cnum = conn?conn->cnum:-1; if (conn) { crec.uid = conn->uid; crec.gid = conn->gid; - safe_strcpy(crec.name, - lp_servicename(SNUM(conn)),sizeof(crec.name)-1); + strlcpy(crec.servicename, lp_servicename(SNUM(conn)), + sizeof(crec.servicename)); } crec.start = time(NULL); crec.bcast_msg_flags = msg_flags; - safe_strcpy(crec.machine,get_remote_machine_name(),sizeof(crec.machine)-1); - safe_strcpy(crec.addr,conn?conn->client_address:client_addr(),sizeof(crec.addr)-1); + strlcpy(crec.machine,get_remote_machine_name(),sizeof(crec.machine)); + strlcpy(crec.addr,conn?conn->client_address:client_addr(), + sizeof(crec.addr)); - dbuf.dptr = (char *)&crec; + dbuf.dptr = (uint8 *)&crec; dbuf.dsize = sizeof(crec); - if (tdb_store(tdb, kbuf, dbuf, TDB_REPLACE) != 0) { + status = rec->store(rec, dbuf, TDB_REPLACE); + + TALLOC_FREE(rec); + + if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("claim_connection: tdb_store failed with error %s.\n", - tdb_errorstr(tdb) )); + nt_errstr(status))); return False; } @@ -194,42 +172,150 @@ BOOL claim_connection(connection_struct *conn, const char *name,int max_connecti BOOL register_message_flags(BOOL doreg, uint32 msg_flags) { - struct connections_key key; + struct db_record *rec; struct connections_data *pcrec; - TDB_DATA kbuf, dbuf; - - if (!tdb) - return False; + NTSTATUS status; DEBUG(10,("register_message_flags: %s flags 0x%x\n", doreg ? "adding" : "removing", (unsigned int)msg_flags )); - make_conn_key(NULL, "", &kbuf, &key); + if (!(rec = connections_fetch_entry(NULL, NULL, ""))) { + DEBUG(0, ("connections_fetch_entry failed\n")); + return False; + } - dbuf = tdb_fetch(tdb, kbuf); - if (!dbuf.dptr) { - DEBUG(0,("register_message_flags: tdb_fetch failed\n")); + if (rec->value.dsize != sizeof(struct connections_data)) { + DEBUG(0,("register_message_flags: Got wrong record size\n")); + TALLOC_FREE(rec); return False; } - pcrec = (struct connections_data *)dbuf.dptr; - pcrec->bcast_msg_flags = msg_flags; + pcrec = (struct connections_data *)rec->value.dptr; if (doreg) pcrec->bcast_msg_flags |= msg_flags; else pcrec->bcast_msg_flags &= ~msg_flags; - if (tdb_store(tdb, kbuf, dbuf, TDB_REPLACE) != 0) { - DEBUG(0,("register_message_flags: tdb_store failed with error %s.\n", - tdb_errorstr(tdb) )); - SAFE_FREE(dbuf.dptr); + status = rec->store(rec, rec->value, TDB_REPLACE); + + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0,("register_message_flags: tdb_store failed: %s.\n", + nt_errstr(status))); + TALLOC_FREE(rec); return False; } DEBUG(10,("register_message_flags: new flags 0x%x\n", (unsigned int)pcrec->bcast_msg_flags )); - SAFE_FREE(dbuf.dptr); + TALLOC_FREE(rec); + return True; } + +/********************************************************************* +*********************************************************************/ + +static TDB_DATA* make_pipe_rec_key( struct pipe_open_rec *prec ) +{ + TDB_DATA *kbuf = NULL; + fstring key_string; + + if ( !prec ) + return NULL; + + if ( (kbuf = TALLOC_P(prec, TDB_DATA)) == NULL ) { + return NULL; + } + + snprintf( key_string, sizeof(key_string), "%s/%d/%d", + prec->name, procid_to_pid(&prec->pid), prec->pnum ); + + *kbuf = string_term_tdb_data(talloc_strdup(prec, key_string)); + if (kbuf->dptr == NULL ) + return NULL; + + return kbuf; +} + +/********************************************************************* +*********************************************************************/ + +static void fill_pipe_open_rec( struct pipe_open_rec *prec, smb_np_struct *p ) +{ + prec->pid = pid_to_procid(sys_getpid()); + prec->pnum = p->pnum; + prec->uid = geteuid(); + fstrcpy( prec->name, p->name ); + + return; +} + +/********************************************************************* +*********************************************************************/ + +BOOL store_pipe_opendb( smb_np_struct *p ) +{ + struct db_record *dbrec; + struct pipe_open_rec *prec; + TDB_DATA *key; + TDB_DATA data; + BOOL ret = False; + + if ( (prec = TALLOC_P( NULL, struct pipe_open_rec)) == NULL ) { + DEBUG(0,("store_pipe_opendb: talloc failed!\n")); + return False; + } + + fill_pipe_open_rec( prec, p ); + if ( (key = make_pipe_rec_key( prec )) == NULL ) { + goto done; + } + + data.dptr = (uint8 *)prec; + data.dsize = sizeof(struct pipe_open_rec); + + if (!(dbrec = connections_fetch_record(prec, *key))) { + DEBUG(0, ("connections_fetch_record failed\n")); + goto done; + } + + ret = NT_STATUS_IS_OK(dbrec->store(dbrec, data, TDB_REPLACE)); + +done: + TALLOC_FREE( prec ); + return ret; +} + +/********************************************************************* +*********************************************************************/ + +BOOL delete_pipe_opendb( smb_np_struct *p ) +{ + struct db_record *dbrec; + struct pipe_open_rec *prec; + TDB_DATA *key; + BOOL ret = False; + + if ( (prec = TALLOC_P( NULL, struct pipe_open_rec)) == NULL ) { + DEBUG(0,("store_pipe_opendb: talloc failed!\n")); + return False; + } + + fill_pipe_open_rec( prec, p ); + if ( (key = make_pipe_rec_key( prec )) == NULL ) { + goto done; + } + + if (!(dbrec = connections_fetch_record(prec, *key))) { + DEBUG(0, ("connections_fetch_record failed\n")); + goto done; + } + + ret = NT_STATUS_IS_OK(dbrec->delete_rec(dbrec)); + +done: + TALLOC_FREE( prec ); + return ret; +}