summaryrefslogtreecommitdiff
path: root/source3/smbd
diff options
context:
space:
mode:
Diffstat (limited to 'source3/smbd')
-rw-r--r--source3/smbd/conn.c196
-rw-r--r--source3/smbd/files.c20
-rw-r--r--source3/smbd/server.c137
-rw-r--r--source3/smbd/uid.c2
4 files changed, 227 insertions, 128 deletions
diff --git a/source3/smbd/conn.c b/source3/smbd/conn.c
new file mode 100644
index 0000000000..b110e8d082
--- /dev/null
+++ b/source3/smbd/conn.c
@@ -0,0 +1,196 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Manage connections_struct structures
+ Copyright (C) Andrew Tridgell 1998
+
+ 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
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ 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.
+*/
+
+#include "includes.h"
+
+extern int DEBUGLEVEL;
+
+/* set these to define the limits of the server. NOTE These are on a
+ per-client basis. Thus any one machine can't connect to more than
+ MAX_CONNECTIONS services, but any number of machines may connect at
+ one time. */
+#define MAX_CONNECTIONS 128
+
+static connection_struct *Connections;
+
+/* number of open connections */
+static struct bitmap *bmap;
+static int num_open;
+
+/****************************************************************************
+init the conn structures
+****************************************************************************/
+void conn_init(void)
+{
+ bmap = bitmap_allocate(MAX_CONNECTIONS);
+}
+
+/****************************************************************************
+return the number of open connections
+****************************************************************************/
+int conn_num_open(void)
+{
+ return num_open;
+}
+
+
+/****************************************************************************
+check if a snum is in use
+****************************************************************************/
+BOOL conn_snum_used(int snum)
+{
+ connection_struct *conn;
+ for (conn=Connections;conn;conn=conn->next) {
+ if (conn->service == snum) {
+ return(True);
+ }
+ }
+ return(False);
+}
+
+
+/****************************************************************************
+find a conn given a cnum
+****************************************************************************/
+connection_struct *conn_find(int cnum)
+{
+ connection_struct *conn;
+
+ for (conn=Connections;conn;conn=conn->next) {
+ if (conn->cnum == cnum) return conn;
+ }
+
+ return NULL;
+}
+
+
+/****************************************************************************
+ find first available connection slot, starting from a random position.
+The randomisation stops problems with the server dieing and clients
+thinking the server is still available.
+****************************************************************************/
+connection_struct *conn_new(void)
+{
+ connection_struct *conn;
+ int i;
+
+ i = bitmap_find(bmap, 1);
+
+ if (i == -1) {
+ DEBUG(1,("ERROR! Out of connection structures\n"));
+ return NULL;
+ }
+
+ conn = (connection_struct *)malloc(sizeof(*conn));
+ if (!conn) return NULL;
+
+ memset(conn, 0, sizeof(*conn));
+ conn->cnum = i;
+
+ bitmap_set(bmap, i);
+
+ num_open++;
+
+ string_init(&conn->user,"");
+ string_init(&conn->dirpath,"");
+ string_init(&conn->connectpath,"");
+ string_init(&conn->origpath,"");
+
+ /* hook into the front of the list */
+ if (!Connections) {
+ Connections = conn;
+ } else {
+ Connections->prev = conn;
+ conn->next = Connections;
+ Connections = conn;
+ }
+
+ return conn;
+}
+
+/****************************************************************************
+close all conn structures
+****************************************************************************/
+void conn_close_all(void)
+{
+ connection_struct *conn, *next;
+ for (conn=Connections;conn;conn=next) {
+ next=conn->next;
+ close_cnum(conn, (uint16)-1);
+ }
+}
+
+/****************************************************************************
+idle inactive connections
+****************************************************************************/
+BOOL conn_idle_all(time_t t, int deadtime)
+{
+ BOOL allidle = True;
+ connection_struct *conn, *next;
+
+ for (conn=Connections;conn;conn=next) {
+ next=conn->next;
+ /* close dirptrs on connections that are idle */
+ if ((t-conn->lastused) > DPTR_IDLE_TIMEOUT)
+ dptr_idlecnum(conn);
+
+ if (conn->num_files_open > 0 ||
+ (t-conn->lastused)<deadtime)
+ allidle = False;
+ }
+
+ return allidle;
+}
+
+/****************************************************************************
+free a conn structure
+****************************************************************************/
+void conn_free(connection_struct *conn)
+{
+ if (conn == Connections) {
+ Connections = conn->next;
+ if (Connections) Connections->prev = NULL;
+ } else {
+ conn->prev->next = conn->next;
+ if (conn->next) conn->next->prev = conn->prev;
+ }
+
+ if (conn->ngroups && conn->groups) {
+ free(conn->groups);
+ conn->groups = NULL;
+ conn->ngroups = 0;
+ }
+
+ free_namearray(conn->veto_list);
+ free_namearray(conn->hide_list);
+ free_namearray(conn->veto_oplock_list);
+
+ string_free(&conn->user);
+ string_free(&conn->dirpath);
+ string_free(&conn->connectpath);
+ string_free(&conn->origpath);
+
+ bitmap_clear(bmap, conn->cnum);
+ num_open--;
+
+ memset(conn, 0, sizeof(*conn));
+ free(conn);
+}
diff --git a/source3/smbd/files.c b/source3/smbd/files.c
index e66e53e6ed..7bd5501de5 100644
--- a/source3/smbd/files.c
+++ b/source3/smbd/files.c
@@ -54,7 +54,7 @@ files_struct *file_new(void )
{
int i;
static int first_file;
- files_struct *fsp;
+ files_struct *fsp, *next;
/* we want to give out file handles differently on each new
connection because of a common bug in MS clients where they try to
@@ -76,7 +76,8 @@ files_struct *file_new(void )
* files batch oplocked for quite a long time
* after they have finished with them.
*/
- for (fsp=Files;fsp;fsp=fsp->next) {
+ for (fsp=Files;fsp;fsp=next) {
+ next=fsp->next;
if (attempt_close_oplocked_file(fsp)) {
return file_new();
}
@@ -200,9 +201,10 @@ close all open files for a connection
****************************************************************************/
void file_close_conn(connection_struct *conn)
{
- files_struct *fsp;
+ files_struct *fsp, *next;
- for (fsp=Files;fsp;fsp=fsp->next) {
+ for (fsp=Files;fsp;fsp=next) {
+ next = fsp->next;
if (fsp->conn == conn && fsp->open) {
if (fsp->is_directory)
close_directory(fsp);
@@ -248,9 +250,10 @@ close files open by a specified vuid
****************************************************************************/
void file_close_user(int vuid)
{
- files_struct *fsp;
+ files_struct *fsp, *next;
- for (fsp=Files;fsp;fsp=fsp->next) {
+ for (fsp=Files;fsp;fsp=next) {
+ next=fsp->next;
if ((fsp->vuid == vuid) && fsp->open) {
if(!fsp->is_directory)
close_file(fsp,False);
@@ -301,9 +304,10 @@ sync open files on a connection
****************************************************************************/
void file_sync_all(connection_struct *conn)
{
- files_struct *fsp;
+ files_struct *fsp, *next;
- for (fsp=Files;fsp;fsp=fsp->next) {
+ for (fsp=Files;fsp;fsp=next) {
+ next=fsp->next;
if (fsp->open && conn == fsp->conn) {
sync_file(conn,fsp);
}
diff --git a/source3/smbd/server.c b/source3/smbd/server.c
index f160b590dc..a293075741 100644
--- a/source3/smbd/server.c
+++ b/source3/smbd/server.c
@@ -65,8 +65,6 @@ extern int dcelogin_atmost_once;
*/
extern DOM_SID global_machine_sid;
-static connection_struct Connections[MAX_CONNECTIONS];
-
extern int Protocol;
/*
@@ -81,9 +79,6 @@ int max_send = BUFFER_SIZE;
*/
int max_recv = BUFFER_SIZE;
-/* number of open connections */
-static int num_connections_open = 0;
-
/* Oplock ipc UDP socket. */
int oplock_sock = -1;
uint16 oplock_port = 0;
@@ -2094,7 +2089,7 @@ BOOL become_service(connection_struct *conn,BOOL do_chdir)
static connection_struct *last_conn;
int snum;
- if (!conn || !conn->open) {
+ if (!conn) {
last_conn = NULL;
return(False);
}
@@ -3250,20 +3245,6 @@ BOOL receive_next_smb(int smbfd, int oplockfd, char *inbuf, int bufsize, int tim
}
/****************************************************************************
-check if a snum is in use
-****************************************************************************/
-BOOL snum_used(int snum)
-{
- int i;
- for (i=0;i<MAX_CONNECTIONS;i++) {
- if (Connections[i].open && (Connections[i].service == snum)) {
- return(True);
- }
- }
- return(False);
-}
-
-/****************************************************************************
reload the services file
**************************************************************************/
BOOL reload_services(BOOL test)
@@ -3284,7 +3265,7 @@ BOOL reload_services(BOOL test)
if (test && !lp_file_list_changed())
return(True);
- lp_killunused(snum_used);
+ lp_killunused(conn_snum_used);
ret = lp_load(servicesf,False,False,True);
@@ -3336,42 +3317,6 @@ static void sig_hup(int sig)
BlockSignals(False,SIGHUP);
}
-/****************************************************************************
- find first available connection slot, starting from a random position.
-The randomisation stops problems with the server dieing and clients
-thinking the server is still available.
-****************************************************************************/
-static connection_struct *find_free_connection(int hash)
-{
- int i;
- BOOL used=False;
- hash = (hash % (MAX_CONNECTIONS-2))+1;
-
- again:
-
- for (i=hash+1;i!=hash;) {
- if (!Connections[i].open && Connections[i].used == used) {
- DEBUG(3,("found free connection number %d\n",i));
- memset(&Connections[i], 0, sizeof(&Connections[i]));
- Connections[i].cnum = i;
- return &Connections[i];
- }
- i++;
- if (i == MAX_CONNECTIONS) {
- i = 1;
- }
- }
-
- if (!used) {
- used = !used;
- goto again;
- }
-
- DEBUG(1,("ERROR! Out of connection structures\n"));
-
- return NULL;
-}
-
/****************************************************************************
make a connection to a service
@@ -3462,10 +3407,11 @@ connection_struct *make_connection(char *service,char *user,char *password, int
return NULL;
}
- conn = find_free_connection(str_checksum(service) + str_checksum(user));
+ conn = conn_new();
if (!conn) {
DEBUG(0,("Couldn't find free connection.\n"));
*ecode = ERRnoresource;
+ conn_free(conn);
return NULL;
}
@@ -3475,6 +3421,7 @@ connection_struct *make_connection(char *service,char *user,char *password, int
if (pass == NULL) {
DEBUG(0,( "Couldn't find account %s\n",user));
*ecode = ERRbaduid;
+ conn_free(conn);
return NULL;
}
@@ -3589,6 +3536,7 @@ connection_struct *make_connection(char *service,char *user,char *password, int
False)) {
DEBUG(1,("too many connections - rejected\n"));
*ecode = ERRnoresource;
+ conn_free(conn);
return NULL;
}
@@ -3597,8 +3545,6 @@ connection_struct *make_connection(char *service,char *user,char *password, int
MAXSTATUS,False);
} /* IS_IPC */
- conn->open = True;
-
/* execute any "root preexec = " line */
if (*lp_rootpreexec(SNUM(conn))) {
pstring cmd;
@@ -3610,7 +3556,6 @@ connection_struct *make_connection(char *service,char *user,char *password, int
if (!become_user(conn, conn->vuid)) {
DEBUG(0,("Can't become connected user!\n"));
- conn->open = False;
if (!IS_IPC(conn)) {
yield_connection(conn,
lp_servicename(SNUM(conn)),
@@ -3619,6 +3564,7 @@ connection_struct *make_connection(char *service,char *user,char *password, int
yield_connection(conn,"STATUS.",MAXSTATUS);
}
}
+ conn_free(conn);
*ecode = ERRbadpw;
return NULL;
}
@@ -3626,7 +3572,6 @@ connection_struct *make_connection(char *service,char *user,char *password, int
if (ChDir(conn->connectpath) != 0) {
DEBUG(0,("Can't change directory to %s (%s)\n",
conn->connectpath,strerror(errno)));
- conn->open = False;
unbecome_user();
if (!IS_IPC(conn)) {
yield_connection(conn,
@@ -3635,6 +3580,7 @@ connection_struct *make_connection(char *service,char *user,char *password, int
if (lp_status(SNUM(conn)))
yield_connection(conn,"STATUS.",MAXSTATUS);
}
+ conn_free(conn);
*ecode = ERRinvnetname;
return NULL;
}
@@ -3652,7 +3598,6 @@ connection_struct *make_connection(char *service,char *user,char *password, int
}
#endif
- num_connections_open++;
add_session_user(user);
/* execute any "preexec = " line */
@@ -4108,11 +4053,6 @@ void close_cnum(connection_struct *conn, uint16 vuid)
unbecome_user();
- if (!conn->open) {
- DEBUG(0,("cnum not open\n"));
- return;
- }
-
DEBUG(IS_IPC(conn)?3:1, ("%s (%s) closed connection to service %s\n",
remote_machine,client_addr(Client),
lp_servicename(SNUM(conn))));
@@ -4146,21 +4086,7 @@ void close_cnum(connection_struct *conn, uint16 vuid)
smbrun(cmd,NULL,False);
}
- conn->open = False;
- num_connections_open--;
- if (conn->ngroups && conn->groups) {
- free(conn->groups);
- conn->groups = NULL;
- conn->ngroups = 0;
- }
-
- free_namearray(conn->veto_list);
- free_namearray(conn->hide_list);
- free_namearray(conn->veto_oplock_list);
-
- string_set(&conn->user,"");
- string_set(&conn->dirpath,"");
- string_set(&conn->connectpath,"");
+ conn_free(conn);
}
@@ -4208,16 +4134,15 @@ exit the server
void exit_server(char *reason)
{
static int firsttime=1;
- int i;
if (!firsttime) exit(0);
firsttime = 0;
unbecome_user();
DEBUG(2,("Closing connections\n"));
- for (i=0;i<MAX_CONNECTIONS;i++)
- if (Connections[i].open)
- close_cnum(&Connections[i],(uint16)-1);
+
+ conn_close_all();
+
#ifdef WITH_DFS
if (dcelogin_atmost_once) {
dfs_unlogin();
@@ -4457,16 +4382,12 @@ static int switch_message(int type,char *inbuf,char *outbuf,int size,int bufsize
if (smb_messages[match].fn)
{
- int cnum = SVAL(inbuf,smb_tid);
int flags = smb_messages[match].flags;
static uint16 last_session_tag = UID_FIELD_INVALID;
/* In share mode security we must ignore the vuid. */
uint16 session_tag = (lp_security() == SEC_SHARE) ? UID_FIELD_INVALID : SVAL(inbuf,smb_uid);
- connection_struct *conn = NULL;
+ connection_struct *conn = conn_find(SVAL(inbuf,smb_tid));
- if (VALID_CNUM(cnum) && Connections[cnum].open) {
- conn = &Connections[cnum];
- }
/* Ensure this value is replaced in the incoming packet. */
SSVAL(inbuf,smb_uid,session_tag);
@@ -4517,7 +4438,7 @@ static int switch_message(int type,char *inbuf,char *outbuf,int size,int bufsize
}
/* load service specific parameters */
- if (OPEN_CONN(conn) &&
+ if (conn &&
!become_service(conn,(flags & AS_USER)?True:False)) {
return(ERROR(ERRSRV,ERRaccess));
}
@@ -4765,7 +4686,6 @@ static void process(void)
InBuffer,BUFFER_SIZE,SMBD_SELECT_LOOP*1000,&got_smb);
counter += SMBD_SELECT_LOOP)
{
- int i;
time_t t;
BOOL allidle = True;
extern int keepalive;
@@ -4816,7 +4736,7 @@ static void process(void)
}
/* automatic timeout if all connections are closed */
- if (num_connections_open==0 && counter >= IDLE_CLOSED_TIMEOUT)
+ if (conn_num_open()==0 && counter >= IDLE_CLOSED_TIMEOUT)
{
DEBUG( 2, ( "Closing idle connection\n" ) );
return;
@@ -4837,19 +4757,9 @@ static void process(void)
}
/* check for connection timeouts */
- for (i=0;i<MAX_CONNECTIONS;i++) {
- if (Connections[i].open) {
- /* close dirptrs on connections that are idle */
- if ((t-Connections[i].lastused)>DPTR_IDLE_TIMEOUT)
- dptr_idlecnum(&Connections[i]);
-
- if (Connections[i].num_files_open > 0 ||
- (t-Connections[i].lastused)<deadtime)
- allidle = False;
- }
- }
+ allidle = conn_idle_all(t, deadtime);
- if (allidle && num_connections_open>0) {
+ if (allidle && conn_num_open()>0) {
DEBUG(2,("Closing idle connection 2.\n"));
return;
}
@@ -4920,7 +4830,6 @@ machine %s in domain %s.\n", global_myname, global_myworkgroup ));
****************************************************************************/
static void init_structs(void )
{
- int i;
get_myname(myhostname,NULL);
/*
@@ -4938,17 +4847,7 @@ static void init_structs(void )
}
strupper( global_myname );
- for (i=0;i<MAX_CONNECTIONS;i++)
- {
- Connections[i].open = False;
- Connections[i].num_files_open=0;
- Connections[i].lastused=0;
- Connections[i].used=False;
- string_init(&Connections[i].user,"");
- string_init(&Connections[i].dirpath,"");
- string_init(&Connections[i].connectpath,"");
- string_init(&Connections[i].origpath,"");
- }
+ conn_init();
file_init();
diff --git a/source3/smbd/uid.c b/source3/smbd/uid.c
index 08a3952b3a..4ffec90521 100644
--- a/source3/smbd/uid.c
+++ b/source3/smbd/uid.c
@@ -236,7 +236,7 @@ BOOL become_user(connection_struct *conn, uint16 vuid)
unbecome_user();
- if (!(conn && conn->open)) {
+ if (!conn) {
DEBUG(2,("Connection not open\n"));
return(False);
}