process.c

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

C
1,793
字号
/* 0xe9 */ { NULL, NULL, 0 },/* 0xea */ { NULL, NULL, 0 },/* 0xeb */ { NULL, NULL, 0 },/* 0xec */ { NULL, NULL, 0 },/* 0xed */ { NULL, NULL, 0 },/* 0xee */ { NULL, NULL, 0 },/* 0xef */ { NULL, NULL, 0 },/* 0xf0 */ { NULL, NULL, 0 },/* 0xf1 */ { NULL, NULL, 0 },/* 0xf2 */ { NULL, NULL, 0 },/* 0xf3 */ { NULL, NULL, 0 },/* 0xf4 */ { NULL, NULL, 0 },/* 0xf5 */ { NULL, NULL, 0 },/* 0xf6 */ { NULL, NULL, 0 },/* 0xf7 */ { NULL, NULL, 0 },/* 0xf8 */ { NULL, NULL, 0 },/* 0xf9 */ { NULL, NULL, 0 },/* 0xfa */ { NULL, NULL, 0 },/* 0xfb */ { NULL, NULL, 0 },/* 0xfc */ { NULL, NULL, 0 },/* 0xfd */ { NULL, NULL, 0 },/* 0xfe */ { NULL, NULL, 0 },/* 0xff */ { NULL, NULL, 0 }};/******************************************************************* Dump a packet to a file.********************************************************************/static void smb_dump(const char *name, int type, char *data, ssize_t len){	int fd, i;	pstring fname;	if (DEBUGLEVEL < 50) return;	if (len < 4) len = smb_len(data)+4;	for (i=1;i<100;i++) {		slprintf(fname,sizeof(fname)-1, "/tmp/%s.%d.%s", name, i,				type ? "req" : "resp");		fd = open(fname, O_WRONLY|O_CREAT|O_EXCL, 0644);		if (fd != -1 || errno != EEXIST) break;	}	if (fd != -1) {		ssize_t ret = write(fd, data, len);		if (ret != len)			DEBUG(0,("smb_dump: problem: write returned %d\n", (int)ret ));		close(fd);		DEBUG(0,("created %s len %lu\n", fname, (unsigned long)len));	}}/**************************************************************************** Do a switch on the message type, and return the response size****************************************************************************/static int switch_message(int type,char *inbuf,char *outbuf,int size,int bufsize){	static pid_t pid= (pid_t)-1;	int outsize = 0;	type &= 0xff;	if (pid == (pid_t)-1)		pid = sys_getpid();	errno = 0;	set_saved_ntstatus(NT_STATUS_OK);	last_message = type;	/* Make sure this is an SMB packet. smb_size contains NetBIOS header so subtract 4 from it. */	if ((strncmp(smb_base(inbuf),"\377SMB",4) != 0) || (size < (smb_size - 4))) {		DEBUG(2,("Non-SMB packet of length %d. Terminating server\n",smb_len(inbuf)));		exit_server("Non-SMB packet");		return(-1);	}	/* yuck! this is an interim measure before we get rid of our		current inbuf/outbuf system */	global_smbpid = SVAL(inbuf,smb_pid);	if (smb_messages[type].fn == NULL) {		DEBUG(0,("Unknown message type %d!\n",type));		smb_dump("Unknown", 1, inbuf, size);		outsize = reply_unknown(inbuf,outbuf);	} else {		int flags = smb_messages[type].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 = conn_find(SVAL(inbuf,smb_tid));		DEBUG(3,("switch message %s (pid %d) conn 0x%lx\n",smb_fn_name(type),(int)pid,(unsigned long)conn));		smb_dump(smb_fn_name(type), 1, inbuf, size);		/* Ensure this value is replaced in the incoming packet. */		SSVAL(inbuf,smb_uid,session_tag);		/*		 * Ensure the correct username is in current_user_info.		 * This is a really ugly bugfix for problems with		 * multiple session_setup_and_X's being done and		 * allowing %U and %G substitutions to work correctly.		 * There is a reason this code is done here, don't		 * move it unless you know what you're doing... :-).		 * JRA.		 */		if (session_tag != last_session_tag) {			user_struct *vuser = NULL;			last_session_tag = session_tag;			if(session_tag != UID_FIELD_INVALID)				vuser = get_valid_user_struct(session_tag);           			if(vuser != NULL)				set_current_user_info(&vuser->user);		}		/* does this protocol need to be run as root? */		if (!(flags & AS_USER))			change_to_root_user();		/* does this protocol need a valid tree connection? */		if ((flags & AS_USER) && !conn) {			/* Amazingly, the error code depends on the command (from Samba4). */			if (type == SMBntcreateX) {				return ERROR_NT(NT_STATUS_INVALID_HANDLE);			} else {				return ERROR_DOS(ERRSRV, ERRinvnid);			}		}		/* does this protocol need to be run as the connected user? */		if ((flags & AS_USER) && !change_to_user(conn,session_tag)) {			if (flags & AS_GUEST) 				flags &= ~AS_USER;			else				return(ERROR_FORCE_DOS(ERRSRV,ERRbaduid));		}		/* this code is to work around a bug is MS client 3 without			introducing a security hole - it needs to be able to do			print queue checks as guest if it isn't logged in properly */		if (flags & AS_USER)			flags &= ~AS_GUEST;		/* does it need write permission? */		if ((flags & NEED_WRITE) && !CAN_WRITE(conn))			return(ERROR_DOS(ERRSRV,ERRaccess));		/* ipc services are limited */		if (IS_IPC(conn) && (flags & AS_USER) && !(flags & CAN_IPC))			return(ERROR_DOS(ERRSRV,ERRaccess));	    		/* load service specific parameters */		if (conn) {			if (!set_current_service(conn,SVAL(inbuf,smb_flg),(flags & (AS_USER|DO_CHDIR)?True:False))) {				return(ERROR_DOS(ERRSRV,ERRaccess));			}			conn->num_smb_operations++;		}		/* does this protocol need to be run as guest? */		if ((flags & AS_GUEST) && (!change_to_guest() || 				!check_access(smbd_server_fd(), lp_hostsallow(-1), lp_hostsdeny(-1))))			return(ERROR_DOS(ERRSRV,ERRaccess));		current_inbuf = inbuf; /* In case we need to defer this message in open... */		outsize = smb_messages[type].fn(conn, inbuf,outbuf,size,bufsize);	}	smb_dump(smb_fn_name(type), 0, outbuf, outsize);	return(outsize);}/**************************************************************************** Construct a reply to the incoming packet.****************************************************************************/static int construct_reply(char *inbuf,char *outbuf,int size,int bufsize){	int type = CVAL(inbuf,smb_com);	int outsize = 0;	int msg_type = CVAL(inbuf,0);	GetTimeOfDay(&smb_last_time);	chain_size = 0;	file_chain_reset();	reset_chain_p();	if (msg_type != 0)		return(reply_special(inbuf,outbuf));  	construct_reply_common(inbuf, outbuf);	outsize = switch_message(type,inbuf,outbuf,size,bufsize);	outsize += chain_size;	if(outsize > 4)		smb_setlen(outbuf,outsize - 4);	return(outsize);}/**************************************************************************** Keep track of the number of running smbd's. This functionality is used to 'hard' limit Samba overhead on resource constrained systems. ****************************************************************************/static BOOL process_count_update_successful = False;static int32 increment_smbd_process_count(void){	int32 total_smbds;	if (lp_max_smbd_processes()) {		total_smbds = 0;		if (tdb_change_int32_atomic(conn_tdb_ctx(), "INFO/total_smbds", &total_smbds, 1) == -1)			return 1;		process_count_update_successful = True;		return total_smbds + 1;	}	return 1;}void decrement_smbd_process_count(void){	int32 total_smbds;	if (lp_max_smbd_processes() && process_count_update_successful) {		total_smbds = 1;		tdb_change_int32_atomic(conn_tdb_ctx(), "INFO/total_smbds", &total_smbds, -1);	}}static BOOL smbd_process_limit(void){	int32  total_smbds;		if (lp_max_smbd_processes()) {		/* Always add one to the smbd process count, as exit_server() always		 * subtracts one.		 */		if (!conn_tdb_ctx()) {			DEBUG(0,("smbd_process_limit: max smbd processes parameter set with status parameter not \set. Ignoring max smbd restriction.\n"));			return False;		}		total_smbds = increment_smbd_process_count();		return total_smbds > lp_max_smbd_processes();	}	else		return False;}/**************************************************************************** Process an smb from the client - split out from the smbd_process() code so it can be used by the oplock break code.****************************************************************************/void process_smb(char *inbuf, char *outbuf){	static int trans_num;	int msg_type = CVAL(inbuf,0);	int32 len = smb_len(inbuf);	int nread = len + 4;	DO_PROFILE_INC(smb_count);	if (trans_num == 0) {		/* on the first packet, check the global hosts allow/ hosts		deny parameters before doing any parsing of the packet		passed to us by the client.  This prevents attacks on our		parsing code from hosts not in the hosts allow list */		if (smbd_process_limit() ||				!check_access(smbd_server_fd(), lp_hostsallow(-1), lp_hostsdeny(-1))) {			/* send a negative session response "not listening on calling name" */			static unsigned char buf[5] = {0x83, 0, 0, 1, 0x81};			DEBUG( 1, ( "Connection denied from %s\n", client_addr() ) );			(void)send_smb(smbd_server_fd(),(char *)buf);			exit_server("connection denied");		}	}	DEBUG( 6, ( "got message type 0x%x of len 0x%x\n", msg_type, len ) );	DEBUG( 3, ( "Transaction %d of length %d\n", trans_num, nread ) );	if (msg_type == 0)		show_msg(inbuf);	else if(msg_type == SMBkeepalive)		return; /* Keepalive packet. */	nread = construct_reply(inbuf,outbuf,nread,max_send);      	if(nread > 0) {		if (CVAL(outbuf,0) == 0)			show_msg(outbuf);			if (nread != smb_len(outbuf) + 4) {			DEBUG(0,("ERROR: Invalid message response size! %d %d\n",				nread, smb_len(outbuf)));		} else if (!send_smb(smbd_server_fd(),outbuf)) {			exit_server("process_smb: send_smb failed.");		}	}	trans_num++;}/**************************************************************************** Return a string containing the function name of a SMB command.****************************************************************************/const char *smb_fn_name(int type){	const char *unknown_name = "SMBunknown";	if (smb_messages[type].name == NULL)		return(unknown_name);	return(smb_messages[type].name);}/**************************************************************************** Helper functions for contruct_reply.****************************************************************************/static uint32 common_flags2 = FLAGS2_LONG_PATH_COMPONENTS|FLAGS2_32_BIT_ERROR_CODES;void add_to_common_flags2(uint32 v){	common_flags2 |= v;}void remove_from_common_flags2(uint32 v){	common_flags2 &= ~v;}void construct_reply_common(char *inbuf,char *outbuf){	memset(outbuf,'\0',smb_size);	set_message(outbuf,0,0,True);	SCVAL(outbuf,smb_com,CVAL(inbuf,smb_com));		memcpy(outbuf+4,inbuf+4,4);	SCVAL(outbuf,smb_rcls,SMB_SUCCESS);	SCVAL(outbuf,smb_reh,0);	SCVAL(outbuf,smb_flg, FLAG_REPLY | (CVAL(inbuf,smb_flg) & FLAG_CASELESS_PATHNAMES)); 	SSVAL(outbuf,smb_flg2,		(SVAL(inbuf,smb_flg2) & FLAGS2_UNICODE_STRINGS) |		common_flags2);	SSVAL(outbuf,smb_err,SMB_SUCCESS);	SSVAL(outbuf,smb_tid,SVAL(inbuf,smb_tid));	SSVAL(outbuf,smb_pid,SVAL(inbuf,smb_pid));	SSVAL(outbuf,smb_uid,SVAL(inbuf,smb_uid));	SSVAL(outbuf,smb_mid,SVAL(inbuf,smb_mid));}/**************************************************************************** Construct a chained reply and add it to the already made reply****************************************************************************/int chain_reply(char *inbuf,char *outbuf,int size,int bufsize){	static char *orig_inbuf;	static char *orig_outbuf;	int smb_com1, smb_com2 = CVAL(inbuf,smb_vwv0);	unsigned smb_off2 = SVAL(inbuf,smb_vwv1);	char *inbuf2, *outbuf2;	int outsize2;	char inbuf_saved[smb_wct];	char outbuf_saved[smb_wct];	int outsize = smb_len(outbuf) + 4;	/* maybe its not chained */	if (smb_com2 == 0xFF) {		SCVAL(outbuf,smb_vwv0,0xFF);		return outsize;	}	if (chain_size == 0) {		/* this is the first part of the chain */		orig_inbuf = inbuf;		orig_outbuf = outbuf;	}	/*	 * The original Win95 redirector dies on a reply to	 * a lockingX and read chain unless the chain reply is	 * 4 byte aligned. JRA.	 */	outsize = (outsize + 3) & ~3;	/* we need to tell the client where the next part of the reply will be */	SSVAL(outbuf,smb_vwv1,smb_offset(outbuf+outsize,outbuf));	SCVAL(outbuf,smb_vwv0,smb_com2);	/* remember how much the caller added to the chain, only counting stuff		after the parameter words */	chain_size += outsize - smb_wct;	/* work out pointers into the original packets. The		headers on these need to be filled in */	inbuf2 = orig_inbuf + smb_off2 + 4 - smb_wct;	outbuf2 = orig_outbuf + SVAL(outbuf,smb_vwv1) + 4 - smb_wct;	/* remember the original command type */	smb_com1 = CVAL(orig_inbuf,smb_com);	/* save the data which will be overwritten by the new headers */	memcpy(inbuf_saved,inbuf2,smb_wct);	memcpy(outbuf_saved,outbuf2,smb_wct);	/* give the new packet the same header as the last part of the SMB */	memmove(inbuf2,inbuf,smb_wct);	/* create the in buffer */	SCVAL(inbuf2,smb_com,smb_com2);	/* create the out buffer */	construct_reply_common(inbuf2, outbuf2);	DEBUG(3,("Chained message\n"));	show_msg(inbuf2);	/* process the request */	outsize2 = switch_message(smb_com2,inbuf2,outbuf2,size-chain_size,				bufsize-chain_size);	/* copy the new reply and request headers over the old ones, but		preserve the smb_com field */	memmove(orig_outbuf,outbuf2,smb_wct);	SCVAL(orig_outbuf,smb_com,smb_com1);	/* restore the saved data, being careful not to overwrite any		data from the reply header */

⌨️ 快捷键说明

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