server.c

来自「samba-3.0.22.tar.gz 编译smb服务器的源码」· C语言 代码 · 共 983 行 · 第 1/2 页

C
983
字号
/*    Unix SMB/CIFS implementation.   Main SMB server routines   Copyright (C) Andrew Tridgell		1992-1998   Copyright (C) Martin Pool			2002   Copyright (C) Jelmer Vernooij		2002-2003      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"#ifdef HAVE_SYS_PRCTL_H#include <sys/prctl.h>#endifstatic int am_parent = 1;/* the last message the was processed */int last_message = -1;/* a useful macro to debug the last message processed */#define LAST_MESSAGE() smb_fn_name(last_message)extern struct auth_context *negprot_global_auth_context;extern pstring user_socket_options;extern SIG_ATOMIC_T got_sig_term;extern SIG_ATOMIC_T reload_after_sighup;#ifdef WITH_DFSextern int dcelogin_atmost_once;#endif /* WITH_DFS *//* really we should have a top level context structure that has the   client file descriptor as an element. That would require a major rewrite :(   the following 2 functions are an alternative - they make the file   descriptor private to smbd */static int server_fd = -1;int smbd_server_fd(void){	return server_fd;}static void smbd_set_server_fd(int fd){	server_fd = fd;	client_setfd(fd);}/**************************************************************************** Terminate signal.****************************************************************************/static void sig_term(void){	got_sig_term = 1;	sys_select_signal(SIGTERM);}/**************************************************************************** Catch a sighup.****************************************************************************/static void sig_hup(int sig){	reload_after_sighup = 1;	sys_select_signal(SIGHUP);}/****************************************************************************  Send a SIGTERM to our process group.*****************************************************************************/static void  killkids(void){	if(am_parent) kill(0,SIGTERM);}/**************************************************************************** Process a sam sync message - not sure whether to do this here or somewhere else.****************************************************************************/static void msg_sam_sync(int UNUSED(msg_type), struct process_id UNUSED(pid),			 void *UNUSED(buf), size_t UNUSED(len)){        DEBUG(10, ("** sam sync message received, ignoring\n"));}/**************************************************************************** Process a sam sync replicate message - not sure whether to do this here or somewhere else.****************************************************************************/static void msg_sam_repl(int msg_type, struct process_id pid,			 void *buf, size_t len){        uint32 low_serial;        if (len != sizeof(uint32))                return;        low_serial = *((uint32 *)buf);        DEBUG(3, ("received sam replication message, serial = 0x%04x\n",                  low_serial));}/**************************************************************************** Open the socket communication - inetd.****************************************************************************/static BOOL open_sockets_inetd(void){	/* Started from inetd. fd 0 is the socket. */	/* We will abort gracefully when the client or remote system 	   goes away */	smbd_set_server_fd(dup(0));		/* close our standard file descriptors */	close_low_fds(False); /* Don't close stderr */		set_socket_options(smbd_server_fd(),"SO_KEEPALIVE");	set_socket_options(smbd_server_fd(), user_socket_options);	return True;}static void msg_exit_server(int msg_type, struct process_id src,			    void *buf, size_t len){	exit_server("Got a SHUTDOWN message");}/**************************************************************************** Have we reached the process limit ?****************************************************************************/static BOOL allowable_number_of_smbd_processes(void){	int max_processes = lp_max_smbd_processes();	if (!max_processes)		return True;	{		TDB_CONTEXT *tdb = conn_tdb_ctx();		int32 val;		if (!tdb) {			DEBUG(0,("allowable_number_of_smbd_processes: can't open connection tdb.\n" ));			return False;		}		val = tdb_fetch_int32(tdb, "INFO/total_smbds");		if (val == -1 && (tdb_error(tdb) != TDB_ERR_NOEXIST)) {			DEBUG(0,("allowable_number_of_smbd_processes: can't fetch INFO/total_smbds. Error %s\n",				tdb_errorstr(tdb) ));			return False;		}		if (val > max_processes) {			DEBUG(0,("allowable_number_of_smbd_processes: number of processes (%d) is over allowed limit (%d)\n",				val, max_processes ));			return False;		}	}	return True;}/**************************************************************************** Open the socket communication.****************************************************************************/static BOOL open_sockets_smbd(BOOL is_daemon, BOOL interactive, const char *smb_ports){	int num_interfaces = iface_count();	int num_sockets = 0;	int fd_listenset[FD_SETSIZE];	fd_set listen_set;	int s;	int maxfd = 0;	int i;	char *ports;	if (!is_daemon) {		return open_sockets_inetd();	}		#ifdef HAVE_ATEXIT	{		static int atexit_set;		if(atexit_set == 0) {			atexit_set=1;			atexit(killkids);		}	}#endif	/* Stop zombies */	CatchChild();					FD_ZERO(&listen_set);	/* use a reasonable default set of ports - listing on 445 and 139 */	if (!smb_ports) {		ports = lp_smb_ports();		if (!ports || !*ports) {			ports = smb_xstrdup(SMB_PORTS);		} else {			ports = smb_xstrdup(ports);		}	} else {		ports = smb_xstrdup(smb_ports);	}	if (lp_interfaces() && lp_bind_interfaces_only()) {		/* We have been given an interfaces line, and been 		   told to only bind to those interfaces. Create a		   socket per interface and bind to only these.		*/				/* Now open a listen socket for each of the		   interfaces. */		for(i = 0; i < num_interfaces; i++) {			struct in_addr *ifip = iface_n_ip(i);			fstring tok;			const char *ptr;			if(ifip == NULL) {				DEBUG(0,("open_sockets_smbd: interface %d has NULL IP address !\n", i));				continue;			}			for (ptr=ports; next_token(&ptr, tok, " \t,", sizeof(tok)); ) {				unsigned port = atoi(tok);				if (port == 0) {					continue;				}				s = fd_listenset[num_sockets] = open_socket_in(SOCK_STREAM, port, 0, ifip->s_addr, True);				if(s == -1)					return False;				/* ready to listen */				set_socket_options(s,"SO_KEEPALIVE"); 				set_socket_options(s,user_socket_options);     				/* Set server socket to non-blocking for the accept. */				set_blocking(s,False);  				if (listen(s, SMBD_LISTEN_BACKLOG) == -1) {					DEBUG(0,("listen: %s\n",strerror(errno)));					close(s);					return False;				}				FD_SET(s,&listen_set);				maxfd = MAX( maxfd, s);				num_sockets++;				if (num_sockets >= FD_SETSIZE) {					DEBUG(0,("open_sockets_smbd: Too many sockets to bind to\n"));					return False;				}			}		}	} else {		/* Just bind to 0.0.0.0 - accept connections		   from anywhere. */		fstring tok;		const char *ptr;		num_interfaces = 1;				for (ptr=ports; next_token(&ptr, tok, " \t,", sizeof(tok)); ) {			unsigned port = atoi(tok);			if (port == 0) continue;			/* open an incoming socket */			s = open_socket_in(SOCK_STREAM, port, 0,					   interpret_addr(lp_socket_address()),True);			if (s == -1)				return(False);					/* ready to listen */			set_socket_options(s,"SO_KEEPALIVE"); 			set_socket_options(s,user_socket_options);						/* Set server socket to non-blocking for the accept. */			set_blocking(s,False);  			if (listen(s, SMBD_LISTEN_BACKLOG) == -1) {				DEBUG(0,("open_sockets_smbd: listen: %s\n",					 strerror(errno)));				close(s);				return False;			}			fd_listenset[num_sockets] = s;			FD_SET(s,&listen_set);			maxfd = MAX( maxfd, s);			num_sockets++;			if (num_sockets >= FD_SETSIZE) {				DEBUG(0,("open_sockets_smbd: Too many sockets to bind to\n"));				return False;			}		}	} 	SAFE_FREE(ports);        /* Listen to messages */        message_register(MSG_SMB_SAM_SYNC, msg_sam_sync);        message_register(MSG_SMB_SAM_REPL, msg_sam_repl);        message_register(MSG_SHUTDOWN, msg_exit_server);	/* now accept incoming connections - forking a new process	   for each incoming connection */	DEBUG(2,("waiting for a connection\n"));	while (1) {		fd_set lfds;		int num;				/* Free up temporary memory from the main smbd. */		lp_talloc_free();		/* Ensure we respond to PING and DEBUG messages from the main smbd. */		message_dispatch();		memcpy((char *)&lfds, (char *)&listen_set, 		       sizeof(listen_set));				num = sys_select(maxfd+1,&lfds,NULL,NULL,NULL);				if (num == -1 && errno == EINTR) {			if (got_sig_term) {				exit_server("Caught TERM signal");			}			/* check for sighup processing */			if (reload_after_sighup) {				change_to_root_user();				DEBUG(1,("Reloading services after SIGHUP\n"));				reload_services(False);				reload_after_sighup = 0;			}			continue;		}				/* check if we need to reload services */		check_reload(time(NULL));		/* Find the sockets that are read-ready -		   accept on these. */		for( ; num > 0; num--) {			struct sockaddr addr;			socklen_t in_addrlen = sizeof(addr);			s = -1;			for(i = 0; i < num_sockets; i++) {				if(FD_ISSET(fd_listenset[i],&lfds)) {					s = fd_listenset[i];					/* Clear this so we don't look					   at it again. */					FD_CLR(fd_listenset[i],&lfds);					break;				}			}			smbd_set_server_fd(accept(s,&addr,&in_addrlen));						if (smbd_server_fd() == -1 && errno == EINTR)				continue;						if (smbd_server_fd() == -1) {				DEBUG(0,("open_sockets_smbd: accept: %s\n",					 strerror(errno)));				continue;			}			/* Ensure child is set to blocking mode */			set_blocking(smbd_server_fd(),True);			if (smbd_server_fd() != -1 && interactive)				return True;						if (allowable_number_of_smbd_processes() && smbd_server_fd() != -1 && sys_fork()==0) {				/* Child code ... */								/* close the listening socket(s) */				for(i = 0; i < num_sockets; i++)					close(fd_listenset[i]);								/* close our standard file				   descriptors */				close_low_fds(False);				am_parent = 0;								set_socket_options(smbd_server_fd(),"SO_KEEPALIVE");				set_socket_options(smbd_server_fd(),user_socket_options);								/* this is needed so that we get decent entries				   in smbstatus for port 445 connects */				set_remote_machine_name(get_peer_addr(smbd_server_fd()), False);								/* Reset the state of the random				 * number generation system, so				 * children do not get the same random				 * numbers as each other */				set_need_random_reseed();				/* tdb needs special fork handling - remove CLEAR_IF_FIRST flags */				if (tdb_reopen_all() == -1) {					DEBUG(0,("tdb_reopen_all failed.\n"));					smb_panic("tdb_reopen_all failed.");				}				return True; 			}			/* The parent doesn't need this socket */			close(smbd_server_fd()); 			/* Sun May 6 18:56:14 2001 ackley@cs.unm.edu:				Clear the closed fd info out of server_fd --				and more importantly, out of client_fd in				util_sock.c, to avoid a possible				getpeername failure if we reopen the logs				and use %I in the filename.			*/			smbd_set_server_fd(-1);			/* Force parent to check log size after			 * spawning child.  Fix from			 * klausr@ITAP.Physik.Uni-Stuttgart.De.  The			 * parent smbd will log to logserver.smb.  It			 * writes only two messages for each child			 * started/finished. But each child writes,			 * say, 50 messages also in logserver.smb,			 * begining with the debug_count of the			 * parent, before the child opens its own log			 * file logserver.client. In a worst case			 * scenario the size of logserver.smb would be			 * checked after about 50*50=2500 messages			 * (ca. 100kb).			 * */			force_check_log_size(); 		} /* end for num */	} /* end while 1 *//* NOTREACHED	return True; */}/**************************************************************************** Reload printers**************************************************************************/void reload_printers(void){	int snum;	int n_services = lp_numservices();	int pnum = lp_servicenumber(PRINTERS_NAME);	const char *pname;	pcap_cache_reload();	/* remove stale printers */	for (snum = 0; snum < n_services; snum++) {		/* avoid removing PRINTERS_NAME or non-autoloaded printers */		if (snum == pnum || !(lp_snum_ok(snum) && lp_print_ok(snum) &&		                      lp_autoloaded(snum)))			continue;		pname = lp_printername(snum);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?