From: Steve French Date: Fri, 4 Jul 2003 08:07:32 +0000 (-0700) Subject: Signing fixes part 2 X-Git-Tag: v2.5.75~21^2~28^2 X-Git-Url: http://git.neil.brown.name/?a=commitdiff_plain;h=fdcd7356f9d3c53965ab87d826156369c2d61adc;p=history.git Signing fixes part 2 --- diff --git a/fs/cifs/Makefile b/fs/cifs/Makefile index 76f667fe61af..94fd2b73c451 100644 --- a/fs/cifs/Makefile +++ b/fs/cifs/Makefile @@ -3,4 +3,4 @@ # 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 diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c new file mode 100755 index 000000000000..e7c468f1812d --- /dev/null +++ b/fs/cifs/cifsencrypt.c @@ -0,0 +1,83 @@ +/* + * 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 +#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; +} diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index ae3e49d1de45..f79a0695fb36 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -149,7 +149,9 @@ struct cifsSesInfo { 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 */ @@ -249,6 +251,7 @@ struct mid_q_entry { 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 */ diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index 1e6be8054126..bd9e6183deb2 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h @@ -307,7 +307,13 @@ struct smb_hdr { __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 */ diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index e557442f61fd..ba9d0c64c0e2 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -79,8 +79,7 @@ extern int setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, 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 *); @@ -226,6 +225,10 @@ extern void tconInfoFree(struct cifsTconInfo *); 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, diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 1d2d347e3adb..5761b8349297 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -106,9 +106,6 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) 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); @@ -260,10 +257,13 @@ CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses) 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; @@ -1657,8 +1657,6 @@ CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses, 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; diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index add558cc01af..bd4c4e9a309f 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -641,6 +641,7 @@ int setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, struct nls_tab 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, @@ -690,9 +691,7 @@ int setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, struct nls_tab 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)); @@ -1024,7 +1023,6 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, 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; @@ -1081,9 +1079,9 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, 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) { @@ -1094,7 +1092,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, 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 */ diff --git a/fs/cifs/smbencrypt.c b/fs/cifs/smbencrypt.c index 83e772647425..9c810c517cf0 100644 --- a/fs/cifs/smbencrypt.c +++ b/fs/cifs/smbencrypt.c @@ -520,7 +520,7 @@ cli_caclulate_sign_mac(struct smb_hdr *outbuf, __u8 * mac_key, 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)++; diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 4705a16d9ef5..62d6136f293a 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -154,12 +154,8 @@ smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer, /* 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)); @@ -200,6 +196,12 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, 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)); @@ -247,9 +249,11 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, 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)