[CIFS] acl support part 6

Acked-by: Shirish Pargaonkar <shirishp@us.ibm.com>
CC: Cyrill Gorcunov <gorcunov@gmail.com>
Signed-off-by: Steve French <sfrench@us.ibm.com>
This commit is contained in:
Steve French 2007-10-25 21:17:17 +00:00
parent 44093ca2fe
commit 630f3f0c45
10 changed files with 169 additions and 60 deletions

View file

@ -97,7 +97,7 @@ int match_sid(struct cifs_sid *ctsid)
/* if the two SIDs (roughly equivalent to a UUID for a user or group) are
the same returns 1, if they do not match returns 0 */
int compare_sids(struct cifs_sid *ctsid, struct cifs_sid *cwsid)
int compare_sids(const struct cifs_sid *ctsid, const struct cifs_sid *cwsid)
{
int i;
int num_subauth, num_sat, num_saw;
@ -129,28 +129,77 @@ int compare_sids(struct cifs_sid *ctsid, struct cifs_sid *cwsid)
return (1); /* sids compare/match */
}
void get_mode_from_acl(struct inode * inode, const char * path)
/*
change posix mode to reflect permissions
pmode is the existing mode (we only want to overwrite part of this
bits to set can be: S_IRWXU, S_IRWXG or S_IRWXO ie 00700 or 00070 or 00007
*/
static void access_flags_to_mode(__u32 access_flags, umode_t * pmode,
umode_t bits_to_set)
{
#ifdef CONFIG_CIFS_DEBUG2
cFYI(1, ("access flags 0x%x mode now 0x%x", access_flags, *pmode);
#endif
return;
}
/* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */
void acl_to_uid_mode(struct inode *inode, const char *path)
{
struct cifsFileInfo *open_file;
int unlock_file = FALSE;
int xid;
int rc = -EIO;
__u16 fid;
struct super_block *sb;
struct cifs_sb_info *cifs_sb;
cFYI(1, ("get mode from ACL for %s", path));
if (inode == NULL)
return;
/* find an open readable handle
if handle found
lock handle
else open file
if no open file can not hurt to check if path is null
GetCIFSACL
for all ACEs in ACL {
if U or G or O
inode->i_mode = parse_ace(file_type, UG or O, ace->perms, inode->i_mode)
else continue
}
if handle open close it
else unlock handle */
xid = GetXid();
open_file = find_readable_file(CIFS_I(inode));
if (open_file) {
unlock_file = TRUE;
fid = open_file->netfid;
} else {
int oplock = FALSE;
/* open file */
sb = inode->i_sb;
if (sb == NULL) {
FreeXid(xid);
return;
}
cifs_sb = CIFS_SB(sb);
rc = CIFSSMBOpen(xid, cifs_sb->tcon, path, FILE_OPEN,
GENERIC_READ, 0, &fid, &oplock, NULL,
cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
if (rc != 0) {
cERROR(1, ("Unable to open file to get ACL"));
FreeXid(xid);
return;
}
}
/* rc = CIFSSMBGetCIFSACL(xid, cifs_sb->tcon, fid, pntsd, acllen,
ACL_TYPE_ACCESS); */
if (unlock_file == TRUE)
atomic_dec(&open_file->wrtPending);
else
CIFSSMBClose(xid, cifs_sb->tcon, fid);
/* parse ACEs e.g.
rc = parse_sec_desc(pntsd, acllen, inode);
*/
FreeXid(xid);
return;
}
@ -193,7 +242,8 @@ static void parse_ace(struct cifs_ace *pace, char *end_of_acl)
static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
struct cifs_sid *pownersid, struct cifs_sid *pgrpsid)
struct cifs_sid *pownersid, struct cifs_sid *pgrpsid
struct inode *inode)
{
int i;
int num_aces = 0;
@ -281,7 +331,8 @@ static int parse_sid(struct cifs_sid *psid, char *end_of_acl)
/* Convert CIFS ACL to POSIX form */
int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len)
static int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len,
struct inode *inode)
{
int rc;
struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
@ -310,14 +361,14 @@ int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len)
if (rc)
return rc;
parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr, group_sid_ptr);
parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr, group_sid_ptr, inode);
/* cifscred->uid = owner_sid_ptr->rid;
cifscred->gid = group_sid_ptr->rid;
memcpy((void *)(&(cifscred->osid)), (void *)owner_sid_ptr,
sizeof (struct cifs_sid));
sizeof(struct cifs_sid));
memcpy((void *)(&(cifscred->gsid)), (void *)group_sid_ptr,
sizeof (struct cifs_sid)); */
sizeof(struct cifs_sid)); */
return (0);

View file

@ -61,6 +61,9 @@ extern int checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length);
extern int is_valid_oplock_break(struct smb_hdr *smb, struct TCP_Server_Info *);
extern int is_size_safe_to_change(struct cifsInodeInfo *, __u64 eof);
extern struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *);
#ifdef CONFIG_CIFS_EXPERIMENTAL
extern struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *);
#endif
extern unsigned int smbCalcSize(struct smb_hdr *ptr);
extern unsigned int smbCalcSize_LE(struct smb_hdr *ptr);
extern int decode_negTokenInit(unsigned char *security_blob, int length,
@ -92,7 +95,7 @@ extern int cifs_get_inode_info(struct inode **pinode,
extern int cifs_get_inode_info_unix(struct inode **pinode,
const unsigned char *search_path,
struct super_block *sb, int xid);
extern void get_mode_from_acl(struct inode * inode, const char * search_path);
extern void acl_to_uid_mode(struct inode *inode, const char *search_path);
extern int cifs_mount(struct super_block *, struct cifs_sb_info *, char *,
const char *);
extern int cifs_umount(struct super_block *, struct cifs_sb_info *);
@ -311,7 +314,6 @@ extern void setup_ntlmv2_rsp(struct cifsSesInfo *, char *,
#ifdef CONFIG_CIFS_WEAK_PW_HASH
extern void calc_lanman_hash(struct cifsSesInfo *ses, char *lnm_session_key);
#endif /* CIFS_WEAK_PW_HASH */
extern int parse_sec_desc(struct cifs_ntsd *, int);
extern int CIFSSMBCopy(int xid,
struct cifsTconInfo *source_tcon,
const char *fromName,
@ -336,8 +338,7 @@ extern int CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon,
const void *ea_value, const __u16 ea_value_len,
const struct nls_table *nls_codepage, int remap_special_chars);
extern int CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon,
__u16 fid, char *acl_inf, const int buflen,
const int acl_type /* ACCESS vs. DEFAULT */);
__u16 fid, struct cifs_ntsd **acl_inf, __u32 *buflen);
extern int CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
const unsigned char *searchName,
char *acl_inf, const int buflen, const int acl_type,

View file

@ -2526,12 +2526,15 @@ smb_init_ntransact(const __u16 sub_command, const int setup_count,
static int
validate_ntransact(char *buf, char **ppparm, char **ppdata,
int *pdatalen, int *pparmlen)
__u32 *pdatalen, __u32 *pparmlen)
{
char *end_of_smb;
__u32 data_count, data_offset, parm_count, parm_offset;
struct smb_com_ntransact_rsp *pSMBr;
*pdatalen = 0;
*pparmlen = 0;
if (buf == NULL)
return -EINVAL;
@ -2568,6 +2571,8 @@ validate_ntransact(char *buf, char **ppparm, char **ppdata,
cFYI(1, ("parm count and data count larger than SMB"));
return -EINVAL;
}
*pdatalen = data_count;
*pparmlen = parm_count;
return 0;
}
#endif /* CIFS_EXPERIMENTAL */
@ -3069,8 +3074,7 @@ GetExtAttrOut:
/* Get Security Descriptor (by handle) from remote server for a file or dir */
int
CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
/* BB fix up return info */ char *acl_inf, const int buflen,
const int acl_type)
struct cifs_ntsd **acl_inf, __u32 *pbuflen)
{
int rc = 0;
int buf_type = 0;
@ -3079,6 +3083,9 @@ CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
cFYI(1, ("GetCifsACL"));
*pbuflen = 0;
*acl_inf = NULL;
rc = smb_init_ntransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
8 /* parm len */, tcon, (void **) &pSMB);
if (rc)
@ -3101,34 +3108,52 @@ CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
if (rc) {
cFYI(1, ("Send error in QuerySecDesc = %d", rc));
} else { /* decode response */
struct cifs_ntsd *psec_desc;
__le32 * parm;
int parm_len;
int data_len;
int acl_len;
__u32 parm_len;
__u32 acl_len;
struct smb_com_ntransact_rsp *pSMBr;
char *pdata;
/* validate_nttransact */
rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
(char **)&psec_desc,
&parm_len, &data_len);
&pdata, &parm_len, pbuflen);
if (rc)
goto qsec_out;
pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
cFYI(1, ("smb %p parm %p data %p", pSMBr, parm, psec_desc));
cFYI(1, ("smb %p parm %p data %p", pSMBr, parm, *acl_inf));
if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
rc = -EIO; /* bad smb */
*pbuflen = 0;
goto qsec_out;
}
/* BB check that data area is minimum length and as big as acl_len */
acl_len = le32_to_cpu(*parm);
/* BB check if (acl_len > bufsize) */
if (acl_len != *pbuflen) {
cERROR(1, ("acl length %d does not match %d",
acl_len, *pbuflen));
if (*pbuflen > acl_len)
*pbuflen = acl_len;
}
parse_sec_desc(psec_desc, acl_len);
/* check if buffer is big enough for the acl
header followed by the smallest SID */
if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
(*pbuflen >= 64 * 1024)) {
cERROR(1, ("bad acl length %d", *pbuflen));
rc = -EINVAL;
*pbuflen = 0;
} else {
*acl_inf = kmalloc(*pbuflen, GFP_KERNEL);
if (*acl_inf == NULL) {
*pbuflen = 0;
rc = -ENOMEM;
}
memcpy(*acl_inf, pdata, *pbuflen);
}
}
qsec_out:
if (buf_type == CIFS_SMALL_BUFFER)
@ -3383,7 +3408,7 @@ UnixQPathInfoRetry:
memcpy((char *) pFindData,
(char *) &pSMBr->hdr.Protocol +
data_offset,
sizeof (FILE_UNIX_BASIC_INFO));
sizeof(FILE_UNIX_BASIC_INFO));
}
}
cifs_buf_release(pSMB);
@ -3651,7 +3676,7 @@ int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
pSMB->SearchHandle = searchHandle; /* always kept as le */
pSMB->SearchCount =
cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_UNIX_INFO));
cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
pSMB->ResumeKey = psrch_inf->resume_key;
pSMB->SearchFlags =
@ -4333,7 +4358,7 @@ QFSDeviceRetry:
} else { /* decode response */
rc = validate_t2((struct smb_t2_rsp *)pSMBr);
if (rc || (pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO)))
if (rc || (pSMBr->ByteCount < sizeof(FILE_SYSTEM_DEVICE_INFO)))
rc = -EIO; /* bad smb */
else {
__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);

View file

@ -1026,6 +1026,37 @@ static ssize_t cifs_write(struct file *file, const char *write_data,
return total_written;
}
#ifdef CONFIG_CIFS_EXPERIMENTAL
struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode)
{
struct cifsFileInfo *open_file = NULL;
read_lock(&GlobalSMBSeslock);
/* we could simply get the first_list_entry since write-only entries
are always at the end of the list but since the first entry might
have a close pending, we go through the whole list */
list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
if (open_file->closePend)
continue;
if (open_file->pfile && ((open_file->pfile->f_flags & O_RDWR) ||
(open_file->pfile->f_flags & O_RDONLY))) {
if (!open_file->invalidHandle) {
/* found a good file */
/* lock it so it will not be closed on us */
atomic_inc(&open_file->wrtPending);
read_unlock(&GlobalSMBSeslock);
return open_file;
} /* else might as well continue, and look for
another, or simply have the caller reopen it
again rather than trying to fix this handle */
} else /* write only file */
break; /* write only files are last so must be done */
}
read_unlock(&GlobalSMBSeslock);
return NULL;
}
#endif
struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode)
{
struct cifsFileInfo *open_file;

View file

@ -530,7 +530,7 @@ int cifs_get_inode_info(struct inode **pinode,
#ifdef CONFIG_CIFS_EXPERIMENTAL
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
cFYI(1, ("Getting mode bits from ACL"));
get_mode_from_acl(inode, search_path);
acl_to_uid_mode(inode, search_path);
}
#endif
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {

View file

@ -276,8 +276,8 @@ hmac_md5_init_rfc2104(unsigned char *key, int key_len,
}
/* start out by storing key in pads */
memset(ctx->k_ipad, 0, sizeof (ctx->k_ipad));
memset(ctx->k_opad, 0, sizeof (ctx->k_opad));
memset(ctx->k_ipad, 0, sizeof(ctx->k_ipad));
memset(ctx->k_opad, 0, sizeof(ctx->k_opad));
memcpy(ctx->k_ipad, key, key_len);
memcpy(ctx->k_opad, key, key_len);
@ -307,8 +307,8 @@ hmac_md5_init_limK_to_64(const unsigned char *key, int key_len,
}
/* start out by storing key in pads */
memset(ctx->k_ipad, 0, sizeof (ctx->k_ipad));
memset(ctx->k_opad, 0, sizeof (ctx->k_opad));
memset(ctx->k_ipad, 0, sizeof(ctx->k_ipad));
memset(ctx->k_opad, 0, sizeof(ctx->k_opad));
memcpy(ctx->k_ipad, key, key_len);
memcpy(ctx->k_opad, key, key_len);

View file

@ -73,7 +73,7 @@ sesInfoAlloc(void)
{
struct cifsSesInfo *ret_buf;
ret_buf = kzalloc(sizeof (struct cifsSesInfo), GFP_KERNEL);
ret_buf = kzalloc(sizeof(struct cifsSesInfo), GFP_KERNEL);
if (ret_buf) {
write_lock(&GlobalSMBSeslock);
atomic_inc(&sesInfoAllocCount);
@ -109,7 +109,7 @@ struct cifsTconInfo *
tconInfoAlloc(void)
{
struct cifsTconInfo *ret_buf;
ret_buf = kzalloc(sizeof (struct cifsTconInfo), GFP_KERNEL);
ret_buf = kzalloc(sizeof(struct cifsTconInfo), GFP_KERNEL);
if (ret_buf) {
write_lock(&GlobalSMBSeslock);
atomic_inc(&tconInfoAllocCount);
@ -298,7 +298,7 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
memset(temp, 0, 256); /* bigger than MAX_CIFS_HDR_SIZE */
buffer->smb_buf_length =
(2 * word_count) + sizeof (struct smb_hdr) -
(2 * word_count) + sizeof(struct smb_hdr) -
4 /* RFC 1001 length field does not count */ +
2 /* for bcc field itself */ ;
/* Note that this is the only network field that has to be converted
@ -422,8 +422,8 @@ checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length)
__u32 clc_len; /* calculated length */
cFYI(0, ("checkSMB Length: 0x%x, smb_buf_length: 0x%x", length, len));
if (length < 2 + sizeof (struct smb_hdr)) {
if ((length >= sizeof (struct smb_hdr) - 1)
if (length < 2 + sizeof(struct smb_hdr)) {
if ((length >= sizeof(struct smb_hdr) - 1)
&& (smb->Status.CifsError != 0)) {
smb->WordCount = 0;
/* some error cases do not return wct and bcc */

View file

@ -793,8 +793,8 @@ map_smb_to_linux_error(struct smb_hdr *smb, int logErr)
if (smberrclass == ERRDOS) { /* 1 byte field no need to byte reverse */
for (i = 0;
i <
sizeof (mapping_table_ERRDOS) /
sizeof (struct smb_to_posix_error); i++) {
sizeof(mapping_table_ERRDOS) /
sizeof(struct smb_to_posix_error); i++) {
if (mapping_table_ERRDOS[i].smb_err == 0)
break;
else if (mapping_table_ERRDOS[i].smb_err ==
@ -807,8 +807,8 @@ map_smb_to_linux_error(struct smb_hdr *smb, int logErr)
} else if (smberrclass == ERRSRV) { /* server class of error codes */
for (i = 0;
i <
sizeof (mapping_table_ERRSRV) /
sizeof (struct smb_to_posix_error); i++) {
sizeof(mapping_table_ERRSRV) /
sizeof(struct smb_to_posix_error); i++) {
if (mapping_table_ERRSRV[i].smb_err == 0)
break;
else if (mapping_table_ERRSRV[i].smb_err ==
@ -837,14 +837,14 @@ map_smb_to_linux_error(struct smb_hdr *smb, int logErr)
unsigned int
smbCalcSize(struct smb_hdr *ptr)
{
return (sizeof (struct smb_hdr) + (2 * ptr->WordCount) +
return (sizeof(struct smb_hdr) + (2 * ptr->WordCount) +
2 /* size of the bcc field */ + BCC(ptr));
}
unsigned int
smbCalcSize_LE(struct smb_hdr *ptr)
{
return (sizeof (struct smb_hdr) + (2 * ptr->WordCount) +
return (sizeof(struct smb_hdr) + (2 * ptr->WordCount) +
2 /* size of the bcc field */ + le16_to_cpu(BCC_LE(ptr)));
}

View file

@ -135,7 +135,7 @@ E_md4hash(const unsigned char *passwd, unsigned char *p16)
wpwd[len] = 0; /* Ensure string is null terminated */
/* Calculate length in bytes */
len = _my_wcslen(wpwd) * sizeof (__u16);
len = _my_wcslen(wpwd) * sizeof(__u16);
mdfour(p16, (unsigned char *) wpwd, len);
memset(wpwd, 0, 129 * 2);
@ -167,7 +167,7 @@ nt_lm_owf_gen(char *pwd, unsigned char nt_p16[16], unsigned char p16[16])
E_P16((unsigned char *) passwd, (unsigned char *) p16);
/* clear out local copy of user's password (just being paranoid). */
memset(passwd, '\0', sizeof (passwd));
memset(passwd, '\0', sizeof(passwd));
}
#endif

View file

@ -265,6 +265,8 @@ ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name,
else if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
__u16 fid;
int oplock = FALSE;
struct cifs_ntsd *pacl = NULL;
__u32 buflen = 0;
if (experimEnabled)
rc = CIFSSMBOpen(xid, pTcon, full_path,
FILE_OPEN, GENERIC_READ, 0, &fid,
@ -274,9 +276,8 @@ ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name,
/* else rc is EOPNOTSUPP from above */
if(rc == 0) {
rc = CIFSSMBGetCIFSACL(xid, pTcon, fid,
ea_value, buf_size,
ACL_TYPE_ACCESS);
rc = CIFSSMBGetCIFSACL(xid, pTcon, fid, &pacl,
&buflen);
CIFSSMBClose(xid, pTcon, fid);
}
}