diff options
Diffstat (limited to 'source3/smbd')
-rw-r--r-- | source3/smbd/conn.c | 196 | ||||
-rw-r--r-- | source3/smbd/files.c | 20 | ||||
-rw-r--r-- | source3/smbd/server.c | 137 | ||||
-rw-r--r-- | source3/smbd/uid.c | 2 |
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); } |