Commit d99e86eb authored by Paulo Alcantara's avatar Paulo Alcantara Committed by Steve French
Browse files

cifs: fix mount on old smb servers



The client was sending rfc1002 session request packet with a wrong
length field set, therefore failing to mount shares against old SMB
servers over port 139.

Fix this by calculating the correct length as specified in rfc1002.

Fixes: d7173623 ("cifs: use ALIGN() and round_up() macros")
Cc: stable@vger.kernel.org
Signed-off-by: default avatarPaulo Alcantara (SUSE) <pc@manguebit.com>
Reviewed-by: default avatarRonnie Sahlberg <lsahlber@redhat.com>
Signed-off-by: default avatarSteve French <stfrench@microsoft.com>
parent de036dca
Loading
Loading
Loading
Loading
+35 −59
Original line number Diff line number Diff line
@@ -2843,72 +2843,48 @@ ip_rfc1001_connect(struct TCP_Server_Info *server)
	 * negprot - BB check reconnection in case where second
	 * sessinit is sent but no second negprot
	 */
	struct rfc1002_session_packet *ses_init_buf;
	unsigned int req_noscope_len;
	struct smb_hdr *smb_buf;
	struct rfc1002_session_packet req = {};
	struct smb_hdr *smb_buf = (struct smb_hdr *)&req;
	unsigned int len;

	ses_init_buf = kzalloc(sizeof(struct rfc1002_session_packet),
			       GFP_KERNEL);

	if (ses_init_buf) {
		ses_init_buf->trailer.session_req.called_len = 32;
	req.trailer.session_req.called_len = sizeof(req.trailer.session_req.called_name);

	if (server->server_RFC1001_name[0] != 0)
			rfc1002mangle(ses_init_buf->trailer.
				      session_req.called_name,
		rfc1002mangle(req.trailer.session_req.called_name,
			      server->server_RFC1001_name,
			      RFC1001_NAME_LEN_WITH_NULL);
	else
			rfc1002mangle(ses_init_buf->trailer.
				      session_req.called_name,
		rfc1002mangle(req.trailer.session_req.called_name,
			      DEFAULT_CIFS_CALLED_NAME,
			      RFC1001_NAME_LEN_WITH_NULL);

		ses_init_buf->trailer.session_req.calling_len = 32;
	req.trailer.session_req.calling_len = sizeof(req.trailer.session_req.calling_name);

		/*
		 * calling name ends in null (byte 16) from old smb
		 * convention.
		 */
	/* calling name ends in null (byte 16) from old smb convention */
	if (server->workstation_RFC1001_name[0] != 0)
			rfc1002mangle(ses_init_buf->trailer.
				      session_req.calling_name,
		rfc1002mangle(req.trailer.session_req.calling_name,
			      server->workstation_RFC1001_name,
			      RFC1001_NAME_LEN_WITH_NULL);
	else
			rfc1002mangle(ses_init_buf->trailer.
				      session_req.calling_name,
		rfc1002mangle(req.trailer.session_req.calling_name,
			      "LINUX_CIFS_CLNT",
			      RFC1001_NAME_LEN_WITH_NULL);

		ses_init_buf->trailer.session_req.scope1 = 0;
		ses_init_buf->trailer.session_req.scope2 = 0;
		smb_buf = (struct smb_hdr *)ses_init_buf;

		/* sizeof RFC1002_SESSION_REQUEST with no scopes */
		req_noscope_len = sizeof(struct rfc1002_session_packet) - 2;

		/* == cpu_to_be32(0x81000044) */
		smb_buf->smb_buf_length =
			cpu_to_be32((RFC1002_SESSION_REQUEST << 24) | req_noscope_len);
		rc = smb_send(server, smb_buf, 0x44);
		kfree(ses_init_buf);
	/*
		 * RFC1001 layer in at least one server
		 * requires very short break before negprot
		 * presumably because not expecting negprot
		 * to follow so fast.  This is a simple
		 * solution that works without
		 * complicating the code and causes no
		 * significant slowing down on mount
		 * for everyone else
	 * As per rfc1002, @len must be the number of bytes that follows the
	 * length field of a rfc1002 session request payload.
	 */
		usleep_range(1000, 2000);
	}
	len = sizeof(req) - offsetof(struct rfc1002_session_packet, trailer.session_req);

	smb_buf->smb_buf_length = cpu_to_be32((RFC1002_SESSION_REQUEST << 24) | len);
	rc = smb_send(server, smb_buf, len);
	/*
	 * else the negprot may still work without this
	 * even though malloc failed
	 * RFC1001 layer in at least one server requires very short break before
	 * negprot presumably because not expecting negprot to follow so fast.
	 * This is a simple solution that works without complicating the code
	 * and causes no significant slowing down on mount for everyone else
	 */
	usleep_range(1000, 2000);

	return rc;
}