Loading fs/cifs/README +5 −0 Original line number Diff line number Diff line Loading @@ -527,6 +527,11 @@ A partial list of the supported mount options follows: SFU does). In the future the bottom 9 bits of the mode also will be emulated using queries of the security descriptor (ACL). mfsymlinks Enable support for Minshall+French symlinks (see http://wiki.samba.org/index.php/UNIX_Extensions#Minshall.2BFrench_symlinks) This option is ignored when specified together with the 'sfu' option. Minshall+French symlinks are used even if the server supports the CIFS Unix Extensions. sign Must use packet signing (helps avoid unwanted data modification by intermediate systems in the route). Note that signing does not work with lanman or plaintext authentication. Loading fs/cifs/cifs_dfs_ref.c +12 −9 Original line number Diff line number Diff line Loading @@ -306,6 +306,7 @@ cifs_dfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd) int xid, i; int rc = 0; struct vfsmount *mnt = ERR_PTR(-ENOENT); struct tcon_link *tlink; cFYI(1, "in %s", __func__); BUG_ON(IS_ROOT(dentry)); Loading @@ -315,14 +316,6 @@ cifs_dfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd) dput(nd->path.dentry); nd->path.dentry = dget(dentry); cifs_sb = CIFS_SB(dentry->d_inode->i_sb); ses = cifs_sb->tcon->ses; if (!ses) { rc = -EINVAL; goto out_err; } /* * The MSDFS spec states that paths in DFS referral requests and * responses must be prefixed by a single '\' character instead of Loading @@ -335,10 +328,20 @@ cifs_dfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd) goto out_err; } cifs_sb = CIFS_SB(dentry->d_inode->i_sb); tlink = cifs_sb_tlink(cifs_sb); if (IS_ERR(tlink)) { rc = PTR_ERR(tlink); goto out_err; } ses = tlink_tcon(tlink)->ses; rc = get_dfs_path(xid, ses, full_path + 1, cifs_sb->local_nls, &num_referrals, &referrals, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); cifs_put_tlink(tlink); for (i = 0; i < num_referrals; i++) { int len; dump_referral(referrals+i); Loading fs/cifs/cifs_fs_sb.h +9 −3 Original line number Diff line number Diff line Loading @@ -15,6 +15,8 @@ * the GNU Lesser General Public License for more details. * */ #include <linux/radix-tree.h> #ifndef _CIFS_FS_SB_H #define _CIFS_FS_SB_H Loading @@ -36,10 +38,13 @@ #define CIFS_MOUNT_NOPOSIXBRL 0x2000 /* mandatory not posix byte range lock */ #define CIFS_MOUNT_NOSSYNC 0x4000 /* don't do slow SMBflush on every sync*/ #define CIFS_MOUNT_FSCACHE 0x8000 /* local caching enabled */ #define CIFS_MOUNT_MF_SYMLINKS 0x10000 /* Minshall+French Symlinks enabled */ #define CIFS_MOUNT_MULTIUSER 0x20000 /* multiuser mount */ struct cifs_sb_info { struct cifsTconInfo *tcon; /* primary mount */ struct list_head nested_tcon_q; struct radix_tree_root tlink_tree; #define CIFS_TLINK_MASTER_TAG 0 /* is "master" (mount) tcon */ spinlock_t tlink_tree_lock; struct nls_table *local_nls; unsigned int rsize; unsigned int wsize; Loading @@ -47,12 +52,13 @@ struct cifs_sb_info { gid_t mnt_gid; mode_t mnt_file_mode; mode_t mnt_dir_mode; int mnt_cifs_flags; unsigned int mnt_cifs_flags; int prepathlen; char *prepath; /* relative path under the share to mount to */ #ifdef CONFIG_CIFS_DFS_UPCALL char *mountdata; /* mount options received at mount time */ #endif struct backing_dev_info bdi; struct delayed_work prune_tlinks; }; #endif /* _CIFS_FS_SB_H */ fs/cifs/cifsacl.c +35 −11 Original line number Diff line number Diff line Loading @@ -557,11 +557,16 @@ static struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb, { struct cifs_ntsd *pntsd = NULL; int xid, rc; struct tcon_link *tlink = cifs_sb_tlink(cifs_sb); if (IS_ERR(tlink)) return NULL; xid = GetXid(); rc = CIFSSMBGetCIFSACL(xid, cifs_sb->tcon, fid, &pntsd, pacllen); rc = CIFSSMBGetCIFSACL(xid, tlink_tcon(tlink), fid, &pntsd, pacllen); FreeXid(xid); cifs_put_tlink(tlink); cFYI(1, "GetCIFSACL rc = %d ACL len %d", rc, *pacllen); return pntsd; Loading @@ -574,10 +579,16 @@ static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb, int oplock = 0; int xid, rc; __u16 fid; struct cifsTconInfo *tcon; struct tcon_link *tlink = cifs_sb_tlink(cifs_sb); if (IS_ERR(tlink)) return NULL; tcon = tlink_tcon(tlink); xid = GetXid(); rc = CIFSSMBOpen(xid, cifs_sb->tcon, path, FILE_OPEN, READ_CONTROL, 0, rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, READ_CONTROL, 0, &fid, &oplock, NULL, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); if (rc) { Loading @@ -585,11 +596,12 @@ static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb, goto out; } rc = CIFSSMBGetCIFSACL(xid, cifs_sb->tcon, fid, &pntsd, pacllen); rc = CIFSSMBGetCIFSACL(xid, tcon, fid, &pntsd, pacllen); cFYI(1, "GetCIFSACL rc = %d ACL len %d", rc, *pacllen); CIFSSMBClose(xid, cifs_sb->tcon, fid); CIFSSMBClose(xid, tcon, fid); out: cifs_put_tlink(tlink); FreeXid(xid); return pntsd; } Loading @@ -603,7 +615,7 @@ static struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb, struct cifsFileInfo *open_file = NULL; if (inode) open_file = find_readable_file(CIFS_I(inode)); open_file = find_readable_file(CIFS_I(inode), true); if (!open_file) return get_cifs_acl_by_path(cifs_sb, path, pacllen); Loading @@ -616,10 +628,15 @@ static int set_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb, __u16 fid, struct cifs_ntsd *pnntsd, u32 acllen) { int xid, rc; struct tcon_link *tlink = cifs_sb_tlink(cifs_sb); if (IS_ERR(tlink)) return PTR_ERR(tlink); xid = GetXid(); rc = CIFSSMBSetCIFSACL(xid, cifs_sb->tcon, fid, pnntsd, acllen); rc = CIFSSMBSetCIFSACL(xid, tlink_tcon(tlink), fid, pnntsd, acllen); FreeXid(xid); cifs_put_tlink(tlink); cFYI(DBG2, "SetCIFSACL rc = %d", rc); return rc; Loading @@ -631,10 +648,16 @@ static int set_cifs_acl_by_path(struct cifs_sb_info *cifs_sb, const char *path, int oplock = 0; int xid, rc; __u16 fid; struct cifsTconInfo *tcon; struct tcon_link *tlink = cifs_sb_tlink(cifs_sb); if (IS_ERR(tlink)) return PTR_ERR(tlink); tcon = tlink_tcon(tlink); xid = GetXid(); rc = CIFSSMBOpen(xid, cifs_sb->tcon, path, FILE_OPEN, WRITE_DAC, 0, rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, WRITE_DAC, 0, &fid, &oplock, NULL, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); if (rc) { Loading @@ -642,12 +665,13 @@ static int set_cifs_acl_by_path(struct cifs_sb_info *cifs_sb, const char *path, goto out; } rc = CIFSSMBSetCIFSACL(xid, cifs_sb->tcon, fid, pnntsd, acllen); rc = CIFSSMBSetCIFSACL(xid, tcon, fid, pnntsd, acllen); cFYI(DBG2, "SetCIFSACL rc = %d", rc); CIFSSMBClose(xid, cifs_sb->tcon, fid); CIFSSMBClose(xid, tcon, fid); out: FreeXid(xid); cifs_put_tlink(tlink); return rc; } Loading @@ -661,7 +685,7 @@ static int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen, cFYI(DBG2, "set ACL for %s from mode 0x%x", path, inode->i_mode); open_file = find_readable_file(CIFS_I(inode)); open_file = find_readable_file(CIFS_I(inode), true); if (!open_file) return set_cifs_acl_by_path(cifs_sb, path, pnntsd, acllen); Loading fs/cifs/cifsencrypt.c +129 −17 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ #include "md5.h" #include "cifs_unicode.h" #include "cifsproto.h" #include "ntlmssp.h" #include <linux/ctype.h> #include <linux/random.h> Loading @@ -42,7 +43,7 @@ extern void SMBencrypt(unsigned char *passwd, const unsigned char *c8, unsigned char *p24); static int cifs_calculate_signature(const struct smb_hdr *cifs_pdu, const struct mac_key *key, char *signature) const struct session_key *key, char *signature) { struct MD5Context context; Loading Loading @@ -78,7 +79,7 @@ int cifs_sign_smb(struct smb_hdr *cifs_pdu, struct TCP_Server_Info *server, server->sequence_number++; spin_unlock(&GlobalMid_Lock); rc = cifs_calculate_signature(cifs_pdu, &server->mac_signing_key, rc = cifs_calculate_signature(cifs_pdu, &server->session_key, smb_signature); if (rc) memset(cifs_pdu->Signature.SecuritySignature, 0, 8); Loading @@ -89,7 +90,7 @@ int cifs_sign_smb(struct smb_hdr *cifs_pdu, struct TCP_Server_Info *server, } static int cifs_calc_signature2(const struct kvec *iov, int n_vec, const struct mac_key *key, char *signature) const struct session_key *key, char *signature) { struct MD5Context context; int i; Loading Loading @@ -145,7 +146,7 @@ int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *server, server->sequence_number++; spin_unlock(&GlobalMid_Lock); rc = cifs_calc_signature2(iov, n_vec, &server->mac_signing_key, rc = cifs_calc_signature2(iov, n_vec, &server->session_key, smb_signature); if (rc) memset(cifs_pdu->Signature.SecuritySignature, 0, 8); Loading @@ -156,14 +157,14 @@ int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *server, } int cifs_verify_signature(struct smb_hdr *cifs_pdu, const struct mac_key *mac_key, const struct session_key *session_key, __u32 expected_sequence_number) { unsigned int rc; char server_response_sig[8]; char what_we_think_sig_should_be[20]; if ((cifs_pdu == NULL) || (mac_key == NULL)) if (cifs_pdu == NULL || session_key == NULL) return -EINVAL; if (cifs_pdu->Command == SMB_COM_NEGOTIATE) Loading Loading @@ -192,7 +193,7 @@ int cifs_verify_signature(struct smb_hdr *cifs_pdu, cpu_to_le32(expected_sequence_number); cifs_pdu->Signature.Sequence.Reserved = 0; rc = cifs_calculate_signature(cifs_pdu, mac_key, rc = cifs_calculate_signature(cifs_pdu, session_key, what_we_think_sig_should_be); if (rc) Loading @@ -209,7 +210,7 @@ int cifs_verify_signature(struct smb_hdr *cifs_pdu, } /* We fill in key by putting in 40 byte array which was allocated by caller */ int cifs_calculate_mac_key(struct mac_key *key, const char *rn, int cifs_calculate_session_key(struct session_key *key, const char *rn, const char *password) { char temp_key[16]; Loading Loading @@ -262,6 +263,90 @@ void calc_lanman_hash(const char *password, const char *cryptkey, bool encrypt, } #endif /* CIFS_WEAK_PW_HASH */ /* This is just a filler for ntlmv2 type of security mechanisms. * Older servers are not very particular about the contents of av pairs * in the blob and for sec mechs like ntlmv2, there is no negotiation * as in ntlmssp, so unless domain and server netbios and dns names * are specified, there is no way to obtain name. In case of ntlmssp, * server provides that info in type 2 challenge packet */ static int build_avpair_blob(struct cifsSesInfo *ses) { struct ntlmssp2_name *attrptr; ses->tilen = 2 * sizeof(struct ntlmssp2_name); ses->tiblob = kzalloc(ses->tilen, GFP_KERNEL); if (!ses->tiblob) { ses->tilen = 0; cERROR(1, "Challenge target info allocation failure"); return -ENOMEM; } attrptr = (struct ntlmssp2_name *) ses->tiblob; attrptr->type = cpu_to_le16(NTLMSSP_DOMAIN_TYPE); return 0; } /* Server has provided av pairs/target info in the type 2 challenge * packet and we have plucked it and stored within smb session. * We parse that blob here to find netbios domain name to be used * as part of ntlmv2 authentication (in Target String), if not already * specified on the command line. * If this function returns without any error but without fetching * domain name, authentication may fail against some server but * may not fail against other (those who are not very particular * about target string i.e. for some, just user name might suffice. */ static int find_domain_name(struct cifsSesInfo *ses) { unsigned int attrsize; unsigned int type; unsigned int onesize = sizeof(struct ntlmssp2_name); unsigned char *blobptr; unsigned char *blobend; struct ntlmssp2_name *attrptr; if (!ses->tilen || !ses->tiblob) return 0; blobptr = ses->tiblob; blobend = ses->tiblob + ses->tilen; while (blobptr + onesize < blobend) { attrptr = (struct ntlmssp2_name *) blobptr; type = le16_to_cpu(attrptr->type); if (type == NTLMSSP_AV_EOL) break; blobptr += 2; /* advance attr type */ attrsize = le16_to_cpu(attrptr->length); blobptr += 2; /* advance attr size */ if (blobptr + attrsize > blobend) break; if (type == NTLMSSP_AV_NB_DOMAIN_NAME) { if (!attrsize) break; if (!ses->domainName) { struct nls_table *default_nls; ses->domainName = kmalloc(attrsize + 1, GFP_KERNEL); if (!ses->domainName) return -ENOMEM; default_nls = load_nls_default(); cifs_from_ucs2(ses->domainName, (__le16 *)blobptr, attrsize, attrsize, default_nls, false); unload_nls(default_nls); break; } } blobptr += attrsize; /* advance attr value */ } return 0; } static int calc_ntlmv2_hash(struct cifsSesInfo *ses, const struct nls_table *nls_cp) { Loading Loading @@ -321,7 +406,8 @@ calc_exit_2: return rc; } void setup_ntlmv2_rsp(struct cifsSesInfo *ses, char *resp_buf, int setup_ntlmv2_rsp(struct cifsSesInfo *ses, char *resp_buf, const struct nls_table *nls_cp) { int rc; Loading @@ -333,25 +419,48 @@ void setup_ntlmv2_rsp(struct cifsSesInfo *ses, char *resp_buf, buf->time = cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME)); get_random_bytes(&buf->client_chal, sizeof(buf->client_chal)); buf->reserved2 = 0; buf->names[0].type = cpu_to_le16(NTLMSSP_DOMAIN_TYPE); buf->names[0].length = 0; buf->names[1].type = 0; buf->names[1].length = 0; if (ses->server->secType == RawNTLMSSP) { if (!ses->domainName) { rc = find_domain_name(ses); if (rc) { cERROR(1, "error %d finding domain name", rc); goto setup_ntlmv2_rsp_ret; } } } else { rc = build_avpair_blob(ses); if (rc) { cERROR(1, "error %d building av pair blob", rc); return rc; } } /* calculate buf->ntlmv2_hash */ rc = calc_ntlmv2_hash(ses, nls_cp); if (rc) if (rc) { cERROR(1, "could not get v2 hash rc %d", rc); goto setup_ntlmv2_rsp_ret; } CalcNTLMv2_response(ses, resp_buf); /* now calculate the MAC key for NTLMv2 */ hmac_md5_init_limK_to_64(ses->server->ntlmv2_hash, 16, &context); hmac_md5_update(resp_buf, 16, &context); hmac_md5_final(ses->server->mac_signing_key.data.ntlmv2.key, &context); hmac_md5_final(ses->server->session_key.data.ntlmv2.key, &context); memcpy(&ses->server->mac_signing_key.data.ntlmv2.resp, resp_buf, memcpy(&ses->server->session_key.data.ntlmv2.resp, resp_buf, sizeof(struct ntlmv2_resp)); ses->server->mac_signing_key.len = 16 + sizeof(struct ntlmv2_resp); ses->server->session_key.len = 16 + sizeof(struct ntlmv2_resp); return 0; setup_ntlmv2_rsp_ret: kfree(ses->tiblob); ses->tiblob = NULL; ses->tilen = 0; return rc; } void CalcNTLMv2_response(const struct cifsSesInfo *ses, Loading @@ -365,6 +474,9 @@ void CalcNTLMv2_response(const struct cifsSesInfo *ses, hmac_md5_update(v2_session_response+8, sizeof(struct ntlmv2_resp) - 8, &context); if (ses->tilen) hmac_md5_update(ses->tiblob, ses->tilen, &context); hmac_md5_final(v2_session_response, &context); /* cifs_dump_mem("v2_sess_rsp: ", v2_session_response, 32); */ } Loading
fs/cifs/README +5 −0 Original line number Diff line number Diff line Loading @@ -527,6 +527,11 @@ A partial list of the supported mount options follows: SFU does). In the future the bottom 9 bits of the mode also will be emulated using queries of the security descriptor (ACL). mfsymlinks Enable support for Minshall+French symlinks (see http://wiki.samba.org/index.php/UNIX_Extensions#Minshall.2BFrench_symlinks) This option is ignored when specified together with the 'sfu' option. Minshall+French symlinks are used even if the server supports the CIFS Unix Extensions. sign Must use packet signing (helps avoid unwanted data modification by intermediate systems in the route). Note that signing does not work with lanman or plaintext authentication. Loading
fs/cifs/cifs_dfs_ref.c +12 −9 Original line number Diff line number Diff line Loading @@ -306,6 +306,7 @@ cifs_dfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd) int xid, i; int rc = 0; struct vfsmount *mnt = ERR_PTR(-ENOENT); struct tcon_link *tlink; cFYI(1, "in %s", __func__); BUG_ON(IS_ROOT(dentry)); Loading @@ -315,14 +316,6 @@ cifs_dfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd) dput(nd->path.dentry); nd->path.dentry = dget(dentry); cifs_sb = CIFS_SB(dentry->d_inode->i_sb); ses = cifs_sb->tcon->ses; if (!ses) { rc = -EINVAL; goto out_err; } /* * The MSDFS spec states that paths in DFS referral requests and * responses must be prefixed by a single '\' character instead of Loading @@ -335,10 +328,20 @@ cifs_dfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd) goto out_err; } cifs_sb = CIFS_SB(dentry->d_inode->i_sb); tlink = cifs_sb_tlink(cifs_sb); if (IS_ERR(tlink)) { rc = PTR_ERR(tlink); goto out_err; } ses = tlink_tcon(tlink)->ses; rc = get_dfs_path(xid, ses, full_path + 1, cifs_sb->local_nls, &num_referrals, &referrals, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); cifs_put_tlink(tlink); for (i = 0; i < num_referrals; i++) { int len; dump_referral(referrals+i); Loading
fs/cifs/cifs_fs_sb.h +9 −3 Original line number Diff line number Diff line Loading @@ -15,6 +15,8 @@ * the GNU Lesser General Public License for more details. * */ #include <linux/radix-tree.h> #ifndef _CIFS_FS_SB_H #define _CIFS_FS_SB_H Loading @@ -36,10 +38,13 @@ #define CIFS_MOUNT_NOPOSIXBRL 0x2000 /* mandatory not posix byte range lock */ #define CIFS_MOUNT_NOSSYNC 0x4000 /* don't do slow SMBflush on every sync*/ #define CIFS_MOUNT_FSCACHE 0x8000 /* local caching enabled */ #define CIFS_MOUNT_MF_SYMLINKS 0x10000 /* Minshall+French Symlinks enabled */ #define CIFS_MOUNT_MULTIUSER 0x20000 /* multiuser mount */ struct cifs_sb_info { struct cifsTconInfo *tcon; /* primary mount */ struct list_head nested_tcon_q; struct radix_tree_root tlink_tree; #define CIFS_TLINK_MASTER_TAG 0 /* is "master" (mount) tcon */ spinlock_t tlink_tree_lock; struct nls_table *local_nls; unsigned int rsize; unsigned int wsize; Loading @@ -47,12 +52,13 @@ struct cifs_sb_info { gid_t mnt_gid; mode_t mnt_file_mode; mode_t mnt_dir_mode; int mnt_cifs_flags; unsigned int mnt_cifs_flags; int prepathlen; char *prepath; /* relative path under the share to mount to */ #ifdef CONFIG_CIFS_DFS_UPCALL char *mountdata; /* mount options received at mount time */ #endif struct backing_dev_info bdi; struct delayed_work prune_tlinks; }; #endif /* _CIFS_FS_SB_H */
fs/cifs/cifsacl.c +35 −11 Original line number Diff line number Diff line Loading @@ -557,11 +557,16 @@ static struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb, { struct cifs_ntsd *pntsd = NULL; int xid, rc; struct tcon_link *tlink = cifs_sb_tlink(cifs_sb); if (IS_ERR(tlink)) return NULL; xid = GetXid(); rc = CIFSSMBGetCIFSACL(xid, cifs_sb->tcon, fid, &pntsd, pacllen); rc = CIFSSMBGetCIFSACL(xid, tlink_tcon(tlink), fid, &pntsd, pacllen); FreeXid(xid); cifs_put_tlink(tlink); cFYI(1, "GetCIFSACL rc = %d ACL len %d", rc, *pacllen); return pntsd; Loading @@ -574,10 +579,16 @@ static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb, int oplock = 0; int xid, rc; __u16 fid; struct cifsTconInfo *tcon; struct tcon_link *tlink = cifs_sb_tlink(cifs_sb); if (IS_ERR(tlink)) return NULL; tcon = tlink_tcon(tlink); xid = GetXid(); rc = CIFSSMBOpen(xid, cifs_sb->tcon, path, FILE_OPEN, READ_CONTROL, 0, rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, READ_CONTROL, 0, &fid, &oplock, NULL, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); if (rc) { Loading @@ -585,11 +596,12 @@ static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb, goto out; } rc = CIFSSMBGetCIFSACL(xid, cifs_sb->tcon, fid, &pntsd, pacllen); rc = CIFSSMBGetCIFSACL(xid, tcon, fid, &pntsd, pacllen); cFYI(1, "GetCIFSACL rc = %d ACL len %d", rc, *pacllen); CIFSSMBClose(xid, cifs_sb->tcon, fid); CIFSSMBClose(xid, tcon, fid); out: cifs_put_tlink(tlink); FreeXid(xid); return pntsd; } Loading @@ -603,7 +615,7 @@ static struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb, struct cifsFileInfo *open_file = NULL; if (inode) open_file = find_readable_file(CIFS_I(inode)); open_file = find_readable_file(CIFS_I(inode), true); if (!open_file) return get_cifs_acl_by_path(cifs_sb, path, pacllen); Loading @@ -616,10 +628,15 @@ static int set_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb, __u16 fid, struct cifs_ntsd *pnntsd, u32 acllen) { int xid, rc; struct tcon_link *tlink = cifs_sb_tlink(cifs_sb); if (IS_ERR(tlink)) return PTR_ERR(tlink); xid = GetXid(); rc = CIFSSMBSetCIFSACL(xid, cifs_sb->tcon, fid, pnntsd, acllen); rc = CIFSSMBSetCIFSACL(xid, tlink_tcon(tlink), fid, pnntsd, acllen); FreeXid(xid); cifs_put_tlink(tlink); cFYI(DBG2, "SetCIFSACL rc = %d", rc); return rc; Loading @@ -631,10 +648,16 @@ static int set_cifs_acl_by_path(struct cifs_sb_info *cifs_sb, const char *path, int oplock = 0; int xid, rc; __u16 fid; struct cifsTconInfo *tcon; struct tcon_link *tlink = cifs_sb_tlink(cifs_sb); if (IS_ERR(tlink)) return PTR_ERR(tlink); tcon = tlink_tcon(tlink); xid = GetXid(); rc = CIFSSMBOpen(xid, cifs_sb->tcon, path, FILE_OPEN, WRITE_DAC, 0, rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, WRITE_DAC, 0, &fid, &oplock, NULL, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); if (rc) { Loading @@ -642,12 +665,13 @@ static int set_cifs_acl_by_path(struct cifs_sb_info *cifs_sb, const char *path, goto out; } rc = CIFSSMBSetCIFSACL(xid, cifs_sb->tcon, fid, pnntsd, acllen); rc = CIFSSMBSetCIFSACL(xid, tcon, fid, pnntsd, acllen); cFYI(DBG2, "SetCIFSACL rc = %d", rc); CIFSSMBClose(xid, cifs_sb->tcon, fid); CIFSSMBClose(xid, tcon, fid); out: FreeXid(xid); cifs_put_tlink(tlink); return rc; } Loading @@ -661,7 +685,7 @@ static int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen, cFYI(DBG2, "set ACL for %s from mode 0x%x", path, inode->i_mode); open_file = find_readable_file(CIFS_I(inode)); open_file = find_readable_file(CIFS_I(inode), true); if (!open_file) return set_cifs_acl_by_path(cifs_sb, path, pnntsd, acllen); Loading
fs/cifs/cifsencrypt.c +129 −17 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ #include "md5.h" #include "cifs_unicode.h" #include "cifsproto.h" #include "ntlmssp.h" #include <linux/ctype.h> #include <linux/random.h> Loading @@ -42,7 +43,7 @@ extern void SMBencrypt(unsigned char *passwd, const unsigned char *c8, unsigned char *p24); static int cifs_calculate_signature(const struct smb_hdr *cifs_pdu, const struct mac_key *key, char *signature) const struct session_key *key, char *signature) { struct MD5Context context; Loading Loading @@ -78,7 +79,7 @@ int cifs_sign_smb(struct smb_hdr *cifs_pdu, struct TCP_Server_Info *server, server->sequence_number++; spin_unlock(&GlobalMid_Lock); rc = cifs_calculate_signature(cifs_pdu, &server->mac_signing_key, rc = cifs_calculate_signature(cifs_pdu, &server->session_key, smb_signature); if (rc) memset(cifs_pdu->Signature.SecuritySignature, 0, 8); Loading @@ -89,7 +90,7 @@ int cifs_sign_smb(struct smb_hdr *cifs_pdu, struct TCP_Server_Info *server, } static int cifs_calc_signature2(const struct kvec *iov, int n_vec, const struct mac_key *key, char *signature) const struct session_key *key, char *signature) { struct MD5Context context; int i; Loading Loading @@ -145,7 +146,7 @@ int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *server, server->sequence_number++; spin_unlock(&GlobalMid_Lock); rc = cifs_calc_signature2(iov, n_vec, &server->mac_signing_key, rc = cifs_calc_signature2(iov, n_vec, &server->session_key, smb_signature); if (rc) memset(cifs_pdu->Signature.SecuritySignature, 0, 8); Loading @@ -156,14 +157,14 @@ int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *server, } int cifs_verify_signature(struct smb_hdr *cifs_pdu, const struct mac_key *mac_key, const struct session_key *session_key, __u32 expected_sequence_number) { unsigned int rc; char server_response_sig[8]; char what_we_think_sig_should_be[20]; if ((cifs_pdu == NULL) || (mac_key == NULL)) if (cifs_pdu == NULL || session_key == NULL) return -EINVAL; if (cifs_pdu->Command == SMB_COM_NEGOTIATE) Loading Loading @@ -192,7 +193,7 @@ int cifs_verify_signature(struct smb_hdr *cifs_pdu, cpu_to_le32(expected_sequence_number); cifs_pdu->Signature.Sequence.Reserved = 0; rc = cifs_calculate_signature(cifs_pdu, mac_key, rc = cifs_calculate_signature(cifs_pdu, session_key, what_we_think_sig_should_be); if (rc) Loading @@ -209,7 +210,7 @@ int cifs_verify_signature(struct smb_hdr *cifs_pdu, } /* We fill in key by putting in 40 byte array which was allocated by caller */ int cifs_calculate_mac_key(struct mac_key *key, const char *rn, int cifs_calculate_session_key(struct session_key *key, const char *rn, const char *password) { char temp_key[16]; Loading Loading @@ -262,6 +263,90 @@ void calc_lanman_hash(const char *password, const char *cryptkey, bool encrypt, } #endif /* CIFS_WEAK_PW_HASH */ /* This is just a filler for ntlmv2 type of security mechanisms. * Older servers are not very particular about the contents of av pairs * in the blob and for sec mechs like ntlmv2, there is no negotiation * as in ntlmssp, so unless domain and server netbios and dns names * are specified, there is no way to obtain name. In case of ntlmssp, * server provides that info in type 2 challenge packet */ static int build_avpair_blob(struct cifsSesInfo *ses) { struct ntlmssp2_name *attrptr; ses->tilen = 2 * sizeof(struct ntlmssp2_name); ses->tiblob = kzalloc(ses->tilen, GFP_KERNEL); if (!ses->tiblob) { ses->tilen = 0; cERROR(1, "Challenge target info allocation failure"); return -ENOMEM; } attrptr = (struct ntlmssp2_name *) ses->tiblob; attrptr->type = cpu_to_le16(NTLMSSP_DOMAIN_TYPE); return 0; } /* Server has provided av pairs/target info in the type 2 challenge * packet and we have plucked it and stored within smb session. * We parse that blob here to find netbios domain name to be used * as part of ntlmv2 authentication (in Target String), if not already * specified on the command line. * If this function returns without any error but without fetching * domain name, authentication may fail against some server but * may not fail against other (those who are not very particular * about target string i.e. for some, just user name might suffice. */ static int find_domain_name(struct cifsSesInfo *ses) { unsigned int attrsize; unsigned int type; unsigned int onesize = sizeof(struct ntlmssp2_name); unsigned char *blobptr; unsigned char *blobend; struct ntlmssp2_name *attrptr; if (!ses->tilen || !ses->tiblob) return 0; blobptr = ses->tiblob; blobend = ses->tiblob + ses->tilen; while (blobptr + onesize < blobend) { attrptr = (struct ntlmssp2_name *) blobptr; type = le16_to_cpu(attrptr->type); if (type == NTLMSSP_AV_EOL) break; blobptr += 2; /* advance attr type */ attrsize = le16_to_cpu(attrptr->length); blobptr += 2; /* advance attr size */ if (blobptr + attrsize > blobend) break; if (type == NTLMSSP_AV_NB_DOMAIN_NAME) { if (!attrsize) break; if (!ses->domainName) { struct nls_table *default_nls; ses->domainName = kmalloc(attrsize + 1, GFP_KERNEL); if (!ses->domainName) return -ENOMEM; default_nls = load_nls_default(); cifs_from_ucs2(ses->domainName, (__le16 *)blobptr, attrsize, attrsize, default_nls, false); unload_nls(default_nls); break; } } blobptr += attrsize; /* advance attr value */ } return 0; } static int calc_ntlmv2_hash(struct cifsSesInfo *ses, const struct nls_table *nls_cp) { Loading Loading @@ -321,7 +406,8 @@ calc_exit_2: return rc; } void setup_ntlmv2_rsp(struct cifsSesInfo *ses, char *resp_buf, int setup_ntlmv2_rsp(struct cifsSesInfo *ses, char *resp_buf, const struct nls_table *nls_cp) { int rc; Loading @@ -333,25 +419,48 @@ void setup_ntlmv2_rsp(struct cifsSesInfo *ses, char *resp_buf, buf->time = cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME)); get_random_bytes(&buf->client_chal, sizeof(buf->client_chal)); buf->reserved2 = 0; buf->names[0].type = cpu_to_le16(NTLMSSP_DOMAIN_TYPE); buf->names[0].length = 0; buf->names[1].type = 0; buf->names[1].length = 0; if (ses->server->secType == RawNTLMSSP) { if (!ses->domainName) { rc = find_domain_name(ses); if (rc) { cERROR(1, "error %d finding domain name", rc); goto setup_ntlmv2_rsp_ret; } } } else { rc = build_avpair_blob(ses); if (rc) { cERROR(1, "error %d building av pair blob", rc); return rc; } } /* calculate buf->ntlmv2_hash */ rc = calc_ntlmv2_hash(ses, nls_cp); if (rc) if (rc) { cERROR(1, "could not get v2 hash rc %d", rc); goto setup_ntlmv2_rsp_ret; } CalcNTLMv2_response(ses, resp_buf); /* now calculate the MAC key for NTLMv2 */ hmac_md5_init_limK_to_64(ses->server->ntlmv2_hash, 16, &context); hmac_md5_update(resp_buf, 16, &context); hmac_md5_final(ses->server->mac_signing_key.data.ntlmv2.key, &context); hmac_md5_final(ses->server->session_key.data.ntlmv2.key, &context); memcpy(&ses->server->mac_signing_key.data.ntlmv2.resp, resp_buf, memcpy(&ses->server->session_key.data.ntlmv2.resp, resp_buf, sizeof(struct ntlmv2_resp)); ses->server->mac_signing_key.len = 16 + sizeof(struct ntlmv2_resp); ses->server->session_key.len = 16 + sizeof(struct ntlmv2_resp); return 0; setup_ntlmv2_rsp_ret: kfree(ses->tiblob); ses->tiblob = NULL; ses->tilen = 0; return rc; } void CalcNTLMv2_response(const struct cifsSesInfo *ses, Loading @@ -365,6 +474,9 @@ void CalcNTLMv2_response(const struct cifsSesInfo *ses, hmac_md5_update(v2_session_response+8, sizeof(struct ntlmv2_resp) - 8, &context); if (ses->tilen) hmac_md5_update(ses->tiblob, ses->tilen, &context); hmac_md5_final(v2_session_response, &context); /* cifs_dump_mem("v2_sess_rsp: ", v2_session_response, 32); */ }