⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cifssmb.c

📁 Linux内核自带的cifs模块
💻 C
📖 第 1 页 / 共 5 页
字号:
/* *   fs/cifs/cifssmb.c * *   Copyright (C) International Business Machines  Corp., 2002,2007 *   Author(s): Steve French (sfrench@us.ibm.com) * *   Contains the routines for constructing the SMB PDUs themselves * *   This library is free software; you can redistribute it and/or modify *   it under the terms of the GNU Lesser General Public License as published *   by the Free Software Foundation; either version 2.1 of the License, or *   (at your option) any later version. * *   This library 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 Lesser General Public License for more details. * *   You should have received a copy of the GNU Lesser General Public License *   along with this library; if not, write to the Free Software *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* SMB/CIFS PDU handling routines here - except for leftovers in connect.c   */ /* These are mostly routines that operate on a pathname, or on a tree id     */ /* (mounted volume), but there are eight handle based routines which must be */ /* treated slightly differently for reconnection purposes since we never     */ /* want to reuse a stale file handle and only the caller knows the file info */#include <linux/fs.h>#include <linux/kernel.h>#include <linux/vfs.h>#include <linux/version.h>#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)#include <linux/posix_acl_xattr.h>#endif#include <asm/uaccess.h>#include "cifspdu.h"#include "cifsglob.h"#include "cifsproto.h"#include "cifs_unicode.h"#include "cifs_debug.h"#include "cifsacl.h"#ifdef CONFIG_CIFS_POSIXstatic struct {	int index;	char *name;} protocols[] = {#ifdef CONFIG_CIFS_WEAK_PW_HASH	{LANMAN_PROT, "\2LM1.2X002"},	{LANMAN2_PROT, "\2LANMAN2.1"},#endif /* weak password hashing for legacy clients */	{CIFS_PROT, "\2NT LM 0.12"},	{POSIX_PROT, "\2POSIX 2"},	{BAD_PROT, "\2"}};#elsestatic struct {	int index;	char *name;} protocols[] = {#ifdef CONFIG_CIFS_WEAK_PW_HASH	{LANMAN_PROT, "\2LM1.2X002"},	{LANMAN2_PROT, "\2LANMAN2.1"},#endif /* weak password hashing for legacy clients */	{CIFS_PROT, "\2NT LM 0.12"},	{BAD_PROT, "\2"}};#endif/* define the number of elements in the cifs dialect array */#ifdef CONFIG_CIFS_POSIX#ifdef CONFIG_CIFS_WEAK_PW_HASH#define CIFS_NUM_PROT 4#else#define CIFS_NUM_PROT 2#endif /* CIFS_WEAK_PW_HASH */#else /* not posix */#ifdef CONFIG_CIFS_WEAK_PW_HASH#define CIFS_NUM_PROT 3#else#define CIFS_NUM_PROT 1#endif /* CONFIG_CIFS_WEAK_PW_HASH */#endif /* CIFS_POSIX *//* Mark as invalid, all open files on tree connections since they   were closed when session to server was lost */static void mark_open_files_invalid(struct cifsTconInfo *pTcon){	struct cifsFileInfo *open_file = NULL;	struct list_head *tmp;	struct list_head *tmp1;/* list all files open on tree connection and mark them invalid */	write_lock(&GlobalSMBSeslock);	list_for_each_safe(tmp, tmp1, &pTcon->openFileList) {		open_file = list_entry(tmp, struct cifsFileInfo, tlist);		if (open_file)			open_file->invalidHandle = TRUE;	}	write_unlock(&GlobalSMBSeslock);	/* BB Add call to invalidate_inodes(sb) for all superblocks mounted	   to this tcon */}/* If the return code is zero, this function must fill in request_buf pointer */static intsmall_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,	 void **request_buf /* returned */){	int rc = 0;	/* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so	   check for tcp and smb session status done differently	   for those three - in the calling routine */	if (tcon) {		if (tcon->tidStatus == CifsExiting) {			/* only tree disconnect, open, and write,			(and ulogoff which does not have tcon)			are allowed as we start force umount */			if ((smb_command != SMB_COM_WRITE_ANDX) &&			   (smb_command != SMB_COM_OPEN_ANDX) &&			   (smb_command != SMB_COM_TREE_DISCONNECT)) {				cFYI(1, ("can not send cmd %d while umounting",					smb_command));				return -ENODEV;			}		}		if ((tcon->ses) && (tcon->ses->status != CifsExiting) &&				  (tcon->ses->server)) {			struct nls_table *nls_codepage;				/* Give Demultiplex thread up to 10 seconds to				   reconnect, should be greater than cifs socket				   timeout which is 7 seconds */			while(tcon->ses->server->tcpStatus == CifsNeedReconnect) {#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)				int timeout = 10 * HZ;				while((tcon->ses->server->tcpStatus != CifsGood)						&& (timeout > 0)) {					timeout = interruptible_sleep_on_timeout(						&tcon->ses->server->response_q,						timeout);				}#else				wait_event_interruptible_timeout(tcon->ses->server->response_q,					(tcon->ses->server->tcpStatus == CifsGood), 10 * HZ);#endif				if (tcon->ses->server->tcpStatus == CifsNeedReconnect) {					/* on "soft" mounts we wait once */					if ((tcon->retry == FALSE) ||					   (tcon->ses->status == CifsExiting)) {						cFYI(1, ("gave up waiting on "						      "reconnect in smb_init"));						return -EHOSTDOWN;					} /* else "hard" mount - keep retrying					     until process is killed or server					     comes back on-line */				} else /* TCP session is reestablished now */					break;			}			nls_codepage = load_nls_default();		/* need to prevent multiple threads trying to		simultaneously reconnect the same SMB session */			down(&tcon->ses->sesSem);			if (tcon->ses->status == CifsNeedReconnect)				rc = cifs_setup_session(0, tcon->ses,							nls_codepage);			if (!rc && (tcon->tidStatus == CifsNeedReconnect)) {				mark_open_files_invalid(tcon);				rc = CIFSTCon(0, tcon->ses, tcon->treeName,					      tcon, nls_codepage);				up(&tcon->ses->sesSem);				/* tell server which Unix caps we support */				if (tcon->ses->capabilities & CAP_UNIX)					reset_cifs_unix_caps(0 /* no xid */,						tcon,						NULL /* we do not know sb */,						NULL /* no vol info */);				/* BB FIXME add code to check if wsize needs				   update due to negotiated smb buffer size				   shrinking */				if (rc == 0)					atomic_inc(&tconInfoReconnectCount);				cFYI(1, ("reconnect tcon rc = %d", rc));				/* Removed call to reopen open files here.				   It is safer (and faster) to reopen files				   one at a time as needed in read and write */				/* Check if handle based operation so we				   know whether we can continue or not without				   returning to caller to reset file handle */				switch (smb_command) {					case SMB_COM_READ_ANDX:					case SMB_COM_WRITE_ANDX:					case SMB_COM_CLOSE:					case SMB_COM_FIND_CLOSE2:					case SMB_COM_LOCKING_ANDX: {						unload_nls(nls_codepage);						return -EAGAIN;					}				}			} else {				up(&tcon->ses->sesSem);			}			unload_nls(nls_codepage);		} else {			return -EIO;		}	}	if (rc)		return rc;	*request_buf = cifs_small_buf_get();	if (*request_buf == NULL) {		/* BB should we add a retry in here if not a writepage? */		return -ENOMEM;	}	header_assemble((struct smb_hdr *) *request_buf, smb_command,			tcon, wct);	if (tcon != NULL)		cifs_stats_inc(&tcon->num_smbs_sent);	return rc;}intsmall_smb_init_no_tc(const int smb_command, const int wct,		     struct cifsSesInfo *ses, void **request_buf){	int rc;	struct smb_hdr *buffer;	rc = small_smb_init(smb_command, wct, NULL, request_buf);	if (rc)		return rc;	buffer = (struct smb_hdr *)*request_buf;	buffer->Mid = GetNextMid(ses->server);	if (ses->capabilities & CAP_UNICODE)		buffer->Flags2 |= SMBFLG2_UNICODE;	if (ses->capabilities & CAP_STATUS32)		buffer->Flags2 |= SMBFLG2_ERR_STATUS;	/* uid, tid can stay at zero as set in header assemble */	/* BB add support for turning on the signing when	this function is used after 1st of session setup requests */	return rc;}/* If the return code is zero, this function must fill in request_buf pointer */static intsmb_init(int smb_command, int wct, struct cifsTconInfo *tcon,	 void **request_buf /* returned */ ,	 void **response_buf /* returned */ ){	int rc = 0;	/* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so	   check for tcp and smb session status done differently	   for those three - in the calling routine */	if (tcon) {		if (tcon->tidStatus == CifsExiting) {			/* only tree disconnect, open, and write,			  (and ulogoff which does not have tcon)			  are allowed as we start force umount */			if ((smb_command != SMB_COM_WRITE_ANDX) &&			   (smb_command != SMB_COM_OPEN_ANDX) &&			   (smb_command != SMB_COM_TREE_DISCONNECT)) {				cFYI(1, ("can not send cmd %d while umounting",					smb_command));				return -ENODEV;			}		}		if ((tcon->ses) && (tcon->ses->status != CifsExiting) &&				  (tcon->ses->server)) {			struct nls_table *nls_codepage;				/* Give Demultiplex thread up to 10 seconds to				   reconnect, should be greater than cifs socket				   timeout which is 7 seconds */			while(tcon->ses->server->tcpStatus == CifsNeedReconnect) {#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)				int timeout = 10 * HZ;				while((tcon->ses->server->tcpStatus != CifsGood)						&& (timeout > 0)) {					timeout = interruptible_sleep_on_timeout						(&tcon->ses->server->response_q,						 timeout);				}#else				wait_event_interruptible_timeout(tcon->ses->server->response_q,					(tcon->ses->server->tcpStatus == CifsGood), 10 * HZ);#endif				if (tcon->ses->server->tcpStatus ==						CifsNeedReconnect) {					/* on "soft" mounts we wait once */					if ((tcon->retry == FALSE) ||					   (tcon->ses->status == CifsExiting)) {						cFYI(1, ("gave up waiting on "						      "reconnect in smb_init"));						return -EHOSTDOWN;					} /* else "hard" mount - keep retrying					     until process is killed or server					     comes on-line */				} else /* TCP session is reestablished now */					break;			}			nls_codepage = load_nls_default();		/* need to prevent multiple threads trying to		simultaneously reconnect the same SMB session */			down(&tcon->ses->sesSem);			if (tcon->ses->status == CifsNeedReconnect)				rc = cifs_setup_session(0, tcon->ses,							nls_codepage);			if (!rc && (tcon->tidStatus == CifsNeedReconnect)) {				mark_open_files_invalid(tcon);				rc = CIFSTCon(0, tcon->ses, tcon->treeName,					      tcon, nls_codepage);				up(&tcon->ses->sesSem);				/* tell server which Unix caps we support */				if (tcon->ses->capabilities & CAP_UNIX)					reset_cifs_unix_caps(0 /* no xid */,						tcon,						NULL /* do not know sb */,						NULL /* no vol info */);				/* BB FIXME add code to check if wsize needs				update due to negotiated smb buffer size				shrinking */				if (rc == 0)					atomic_inc(&tconInfoReconnectCount);				cFYI(1, ("reconnect tcon rc = %d", rc));				/* Removed call to reopen open files here.				   It is safer (and faster) to reopen files				   one at a time as needed in read and write */				/* Check if handle based operation so we				   know whether we can continue or not without				   returning to caller to reset file handle */				switch (smb_command) {					case SMB_COM_READ_ANDX:					case SMB_COM_WRITE_ANDX:					case SMB_COM_CLOSE:					case SMB_COM_FIND_CLOSE2:					case SMB_COM_LOCKING_ANDX: {						unload_nls(nls_codepage);						return -EAGAIN;					}				}			} else {				up(&tcon->ses->sesSem);			}			unload_nls(nls_codepage);		} else {			return -EIO;		}	}	if (rc)		return rc;	*request_buf = cifs_buf_get();	if (*request_buf == NULL) {		/* BB should we add a retry in here if not a writepage? */		return -ENOMEM;	}    /* Although the original thought was we needed the response buf for  */    /* potential retries of smb operations it turns out we can determine */    /* from the mid flags when the request buffer can be resent without  */    /* having to use a second distinct buffer for the response */	if (response_buf)		*response_buf = *request_buf;	header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,			wct /*wct */ );	if (tcon != NULL)		cifs_stats_inc(&tcon->num_smbs_sent);	return rc;}static int validate_t2(struct smb_t2_rsp *pSMB){	int rc = -EINVAL;	int total_size;	char *pBCC;	/* check for plausible wct, bcc and t2 data and parm sizes */	/* check for parm and data offset going beyond end of smb */	if (pSMB->hdr.WordCount >= 10) {		if ((le16_to_cpu(pSMB->t2_rsp.ParameterOffset) <= 1024) &&		   (le16_to_cpu(pSMB->t2_rsp.DataOffset) <= 1024)) {			/* check that bcc is at least as big as parms + data */			/* check that bcc is less than negotiated smb buffer */			total_size = le16_to_cpu(pSMB->t2_rsp.ParameterCount);			if (total_size < 512) {				total_size +=					le16_to_cpu(pSMB->t2_rsp.DataCount);				/* BCC le converted in SendReceive */				pBCC = (pSMB->hdr.WordCount * 2) +					sizeof(struct smb_hdr) +					(char *)pSMB;				if ((total_size <= (*(u16 *)pBCC)) &&				   (total_size <					CIFSMaxBufSize+MAX_CIFS_HDR_SIZE)) {					return 0;				}			}		}	}	cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,		sizeof(struct smb_t2_rsp) + 16);	return rc;}intCIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses){	NEGOTIATE_REQ *pSMB;	NEGOTIATE_RSP *pSMBr;	int rc = 0;	int bytes_returned;	int i;	struct TCP_Server_Info *server;

⌨️ 快捷键说明

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