#
obj-$(CONFIG_CIFS) += cifs.o
-cifs-objs := cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o inode.o link.o misc.o netmisc.o smbdes.o smbencrypt.o transport.o asn1.o md4.o md5.o cifs_unicode.o nterr.o xattr.o
+cifs-objs := cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o inode.o link.o misc.o netmisc.o smbdes.o smbencrypt.o transport.o asn1.o md4.o md5.o cifs_unicode.o nterr.o xattr.o cifsencrypt.o
--- /dev/null
+/*
+ * fs/cifs/cifsencrypt.c
+ *
+ * Copyright (c) International Business Machines Corp., 2003
+ * Author(s): Steve French (sfrench@us.ibm.com)
+ *
+ * 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
+ */
+
+#include <linux/fs.h>
+#include "cifspdu.h"
+#include "cifsglob.h"
+#include "cifs_debug.h"
+
+/* Calculate and return the CIFS signature based on the mac key and the smb pdu */
+/* the eight byte signature must be allocated by the caller. */
+/* Note that the smb header signature field on input contains the
+ sequence number before this function is called */
+
+static int cifs_calculate_signature(const struct smb_hdr * cifs_pdu, const char * mac_key, char * signature)
+{
+
+ if((cifs_pdu == NULL) || (signature == NULL))
+ return -EINVAL;
+
+ /* MD5(mac_key, text) */
+ /* return 1st eight bytes in signature */
+
+ return 0;
+}
+
+int cifs_sign_smb(struct smb_hdr * cifs_pdu, struct cifsSesInfo * ses)
+{
+ int rc = 0;
+ char smb_signature[8];
+
+ /* BB remember to initialize sequence number elsewhere and initialize mac_signing key elsewhere BB */
+ /* BB remember to add code to save expected sequence number in midQ entry BB */
+
+ if((cifs_pdu == NULL) || (ses == NULL))
+ return -EINVAL;
+
+ if((le32_to_cpu(cifs_pdu->Flags2) & SMBFLG2_SECURITY_SIGNATURE) == 0)
+ return rc;
+
+ cifs_pdu->Signature.Sequence.SequenceNumber = ses->sequence_number;
+ cifs_pdu->Signature.Sequence.Reserved = 0;
+ rc = cifs_calculate_signature(cifs_pdu, ses->mac_signing_key,smb_signature);
+ if(rc)
+ memset(cifs_pdu->Signature.SecuritySignature, 0, 8);
+ else
+ memcpy(cifs_pdu->Signature.SecuritySignature, smb_signature, 8);
+
+ return rc;
+}
+
+int cifs_verify_signature(const struct smb_hdr * cifs_pdu, const char * mac_key,
+ __u32 expected_sequence_number)
+{
+ unsigned int rc = 0;
+
+ if((cifs_pdu == NULL) || (mac_key == NULL))
+ return -EINVAL;
+
+ /* BB no need to verify negprot or if flag is not on for session (or for frame?? */
+ /* BB what if signatures are supposed to be on for session but server does not
+ send one? BB */
+ /* BB also do not verify oplock breaks for signature */
+
+ return rc;
+}
struct TCP_Server_Info *server; /* pointer to server info */
atomic_t inUse; /* # of CURRENT users of this ses */
enum statusEnum status;
+ __u32 sequence_number; /* needed for CIFS PDU signature */
__u16 ipc_tid; /* special tid for connection to IPC share */
+ char mac_signing_key[CIFS_SESSION_KEY_SIZE];
char *serverOS; /* name of operating system underlying the server */
char *serverNOS; /* name of network operating system that the server is running */
char *serverDomain; /* security realm of server */
struct list_head qhead; /* mids waiting on reply from this server */
__u16 mid; /* multiplex id */
__u16 pid; /* process id */
+ __u32 sequence_number; /* for CIFS signing */
__u16 command; /* smb command code */
struct timeval when_sent; /* time when smb sent */
struct cifsSesInfo *ses; /* smb was sent to this server */
__u8 Flags;
__u16 Flags2; /* note: le */
__u16 PidHigh; /* note: le */
- __u8 SecuritySignature[8]; /* note le */
+ union {
+ struct {
+ __u32 SequenceNumber; /* le */
+ __u32 Reserved; /* zero */
+ } Sequence;
+ __u8 SecuritySignature[8]; /* le */
+ } Signature;
__u8 pad[2];
__u16 Tid;
__u16 Pid; /* note: le */
struct nls_table * nls_info);
extern int CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses);
extern int CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
- char *session_key, char *ntlm_session_key,
- const struct nls_table *);
+ char *ntlm_session_key, const struct nls_table *);
extern int CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses,
char *SecurityBlob,int SecurityBlobLength,
const struct nls_table *);
extern int cifs_demultiplex_thread(struct TCP_Server_Info *);
extern int cifs_reconnect(struct TCP_Server_Info *server);
+extern int cifs_sign_smb(struct smb_hdr *, struct cifsSesInfo *);
+extern int cifs_verify_signature(const struct smb_hdr *, const char * mac_key,
+ __u32 expected_sequence_number);
+
/* BB routines below not implemented yet BB */
extern int CIFSBuildServerList(int xid, char *serverBufferList,
pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
if (extended_security)
pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
- if (sign_CIFS_PDUs) {
- pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
- }
pSMB->ByteCount = strlen(protocols[0].name) + 1;
strncpy(pSMB->DialectsArray, protocols[0].name, 30);
up(&ses->sesSem);
return -EBUSY;
}
- if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
- pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
+
rc = smb_init(SMB_COM_LOGOFF_ANDX, 2, 0 /* no tcon anymore */,
(void **) &pSMB, (void **) &smb_buffer_response);
+
+ if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
+ pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
+
if (rc) {
up(&ses->sesSem);
return rc;
if (ses->capabilities & CAP_DFS) {
pSMB->hdr.Flags2 |= SMBFLG2_DFS;
}
- if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
- pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
if (ses->capabilities & CAP_UNICODE) {
pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
if(pSesInfo->server->maxBuf == 0) /* no need to send on reconnect */
rc = CIFSSMBNegotiate(xid, pSesInfo);
pSesInfo->capabilities = pSesInfo->server->capabilities;
+ pSesInfo->sequence_number = 0;
if (!rc) {
cFYI(1,("Security Mode: 0x%x Capabilities: 0x%x Time Zone: %d",
pSesInfo->server->secMode,
pSesInfo->server->cryptKey,
ntlm_session_key);
rc = CIFSSessSetup(xid, pSesInfo,
- session_key,
- ntlm_session_key,
- nls_info);
+ ntlm_session_key, nls_info);
}
if (rc) {
cERROR(1,("Send error in SessSetup = %d",rc));
int
CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
char session_key[CIFS_SESSION_KEY_SIZE],
- char session_key2[CIFS_SESSION_KEY_SIZE],
const struct nls_table *nls_codepage)
{
struct smb_hdr *smb_buffer;
pSMB->req_no_secext.CaseSensitivePasswordLength =
cpu_to_le16(CIFS_SESSION_KEY_SIZE);
bcc_ptr = pByteArea(smb_buffer);
- /* memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE);
+ /* memcpy(bcc_ptr, (char *) lm_session_key, CIFS_SESSION_KEY_SIZE);
bcc_ptr += CIFS_SESSION_KEY_SIZE; */
- memcpy(bcc_ptr, (char *) session_key2, CIFS_SESSION_KEY_SIZE);
+ memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE);
bcc_ptr += CIFS_SESSION_KEY_SIZE;
if (ses->capabilities & CAP_UNICODE) {
if(user == NULL)
bytes_returned = 0; /* skill null user */
else
- bytes_returned =
+ bytes_returned =
cifs_strtoUCS((wchar_t *) bcc_ptr, user, 100, nls_codepage);
bcc_ptr += 2 * bytes_returned; /* convert num 16 bit words to bytes */
bcc_ptr += 2; /* trailing null */
be32_to_cpu(outbuf->smb_buf_length));
MD5Final(calc_md5_mac, &md5_ctx);
- memcpy(outbuf->SecuritySignature, calc_md5_mac, 8);
+ memcpy(outbuf->Signature.SecuritySignature, calc_md5_mac, 8);
(*send_seq_num)++;
*reply_seq_num = *send_seq_num;
(*send_seq_num)++;
/* smb header is converted in header_assemble. bcc and rest of SMB word
area, and byte area if necessary, is converted to littleendian in
- cifssmb.c and RFC1001 len is converted to bigendian in smb_send */
- if (smb_buf_length > 12)
- smb_buffer->Flags2 = cpu_to_le16(smb_buffer->Flags2);
-
- /* if(smb_buffer->Flags2 & SMBFLG2_SECURITY_SIGNATURE)
- sign_smb(smb_buffer); */ /* BB enable when signing tested more */
+ cifssmb.c and RFC1001 len is converted to bigendian in smb_send
+ Flags2 is converted in SendReceive */
smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length);
cFYI(1, ("Sending smb of length %d ", smb_buf_length));
DeleteMidQEntry(midQ);
return -EIO;
}
+
+ if (in_buf->smb_buf_length > 12)
+ in_buf->Flags2 = cpu_to_le16(in_buf->Flags2);
+
+ rc = cifs_sign_smb(in_buf, ses);
+
midQ->midState = MID_REQUEST_SUBMITTED;
rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length,
(struct sockaddr *) &(ses->server->sockAddr));
memcpy(out_buf, midQ->resp_buf,
receive_len +
4 /* include 4 byte RFC1001 header */ );
- /* convert the length back to a form that we can use */
+/* int cifs_verify_signature(out_buf, ses->mac_signing_key,
+ __u32 expected_sequence_number); */
dump_smb(out_buf, 92);
+ /* convert the length into a more usable form */
out_buf->smb_buf_length =
be32_to_cpu(out_buf->smb_buf_length);
if (out_buf->smb_buf_length > 12)