staticchar *
sid_to_key_str(struct smb_sid *sidptr, unsignedint type)
{ int i, len; unsignedint saval; char *sidstr, *strptr; unsignedlonglong id_auth_val;
/* 3 bytes for prefix */
sidstr = kmalloc(3 + SID_STRING_BASE_SIZE +
(SID_STRING_SUBAUTH_SIZE * sidptr->num_subauth),
GFP_KERNEL); if (!sidstr) return sidstr;
strptr = sidstr;
len = sprintf(strptr, "%cs:S-%hhu", type == SIDOWNER ? 'o' : 'g',
sidptr->revision);
strptr += len;
/* The authority field is a single 48-bit number */
id_auth_val = (unsignedlonglong)sidptr->authority[5];
id_auth_val |= (unsignedlonglong)sidptr->authority[4] << 8;
id_auth_val |= (unsignedlonglong)sidptr->authority[3] << 16;
id_auth_val |= (unsignedlonglong)sidptr->authority[2] << 24;
id_auth_val |= (unsignedlonglong)sidptr->authority[1] << 32;
id_auth_val |= (unsignedlonglong)sidptr->authority[0] << 48;
/* *MS-DTYPstatesthatiftheauthorityis>=2^32,thenitshouldbe *expressedasahexvalue.
*/ if (id_auth_val <= UINT_MAX)
len = sprintf(strptr, "-%llu", id_auth_val); else
len = sprintf(strptr, "-0x%llx", id_auth_val);
strptr += len;
for (i = 0; i < sidptr->num_subauth; ++i) {
saval = le32_to_cpu(sidptr->sub_auth[i]);
len = sprintf(strptr, "-%u", saval);
strptr += len;
}
return sidstr;
}
/* *ifthetwoSIDs(roughlyequivalenttoaUUIDforauserorgroup)are *thesamereturnszero,iftheydonotmatchreturnsnon-zero.
*/ staticint
compare_sids(conststruct smb_sid *ctsid, conststruct smb_sid *cwsid)
{ int i; int num_subauth, num_sat, num_saw;
if ((!ctsid) || (!cwsid)) return1;
/* compare the revision */ if (ctsid->revision != cwsid->revision) { if (ctsid->revision > cwsid->revision) return1; else return -1;
}
/* compare all of the six auth values */ for (i = 0; i < NUM_AUTHS; ++i) { if (ctsid->authority[i] != cwsid->authority[i]) { if (ctsid->authority[i] > cwsid->authority[i]) return1; else return -1;
}
}
/* compare all of the subauth values if any */
num_sat = ctsid->num_subauth;
num_saw = cwsid->num_subauth;
num_subauth = min(num_sat, num_saw); if (num_subauth) { for (i = 0; i < num_subauth; ++i) { if (ctsid->sub_auth[i] != cwsid->sub_auth[i]) { if (le32_to_cpu(ctsid->sub_auth[i]) >
le32_to_cpu(cwsid->sub_auth[i])) return1; else return -1;
}
}
}
return0; /* sids compare/match */
}
staticbool
is_well_known_sid(conststruct smb_sid *psid, uint32_t *puid, bool is_group)
{ int i; int num_subauth; conststruct smb_sid *pwell_known_sid;
if (!psid || (puid == NULL)) returnfalse;
num_subauth = psid->num_subauth;
/* check if Mac (or Windows NFS) vs. Samba format for Unix owner SID */ if (num_subauth == 2) { if (is_group)
pwell_known_sid = &sid_unix_groups; else
pwell_known_sid = &sid_unix_users;
} elseif (num_subauth == 3) { if (is_group)
pwell_known_sid = &sid_unix_NFS_groups; else
pwell_known_sid = &sid_unix_NFS_users;
} else returnfalse;
/* compare the revision */ if (psid->revision != pwell_known_sid->revision) returnfalse;
/* compare all of the six auth values */ for (i = 0; i < NUM_AUTHS; ++i) { if (psid->authority[i] != pwell_known_sid->authority[i]) {
cifs_dbg(FYI, "auth %d did not match\n", i); returnfalse;
}
}
if (num_subauth == 2) { if (psid->sub_auth[0] != pwell_known_sid->sub_auth[0]) returnfalse;
int
init_cifs_idmap(void)
{ struct cred *cred; struct key *keyring; int ret;
cifs_dbg(FYI, "Registering the %s key type\n",
cifs_idmap_key_type.name);
/* create an override credential set with a special thread keyring in *whichrequestsarecached * *thisisusedtopreventmaliciousredirectionsfrombeinginstalled *withadd_key().
*/
cred = prepare_kernel_cred(&init_task); if (!cred) return -ENOMEM;
ret = register_key_type(&cifs_idmap_key_type); if (ret < 0) goto failed_put_key;
/* instruct request_key() to use this special keyring as a cache for
* the results it looks up */
set_bit(KEY_FLAG_ROOT_CAN_CLEAR, &keyring->flags);
cred->thread_keyring = keyring;
cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING;
root_cred = cred;
/* If DELETE_CHILD is set only on an owner ACE, set sticky bit */ if (flags & FILE_DELETE_CHILD) { if (mask == ACL_OWNER_MASK) { if (!(*pdenied & 01000))
*pmode |= 01000;
} elseif (!(*pdenied & 01000)) {
*pmode &= ~01000;
*pdenied |= 01000;
}
}
/* bits to use are either S_IRWXU or S_IRWXG or S_IRWXO */
mode &= bits_to_use;
/* check for R/W/X UGO since we do not know whose flags isthisbutwehaveclearedallthebitssansRWXfor
either user or group or other as per bits_to_use */ if (mode & S_IRUGO)
*pace_flags |= SET_FILE_READ_RIGHTS; if (mode & S_IWUGO)
*pace_flags |= SET_FILE_WRITE_RIGHTS; if (mode & S_IXUGO)
*pace_flags |= SET_FILE_EXEC_RIGHTS;
pntace->sid.revision = psid->revision;
pntace->sid.num_subauth = psid->num_subauth; for (i = 0; i < NUM_AUTHS; i++)
pntace->sid.authority[i] = psid->authority[i]; for (i = 0; i < psid->num_subauth; i++)
pntace->sid.sub_auth[i] = psid->sub_auth[i];
/* BB need to add parm so we can store the SID BB */
if (!pdacl) { /* no DACL in the security descriptor, set
all the permissions for user/group/other */
fattr->cf_mode |= 0777; return;
}
/* validate that we do not go past end of acl */ if (end_of_acl < (char *)pdacl + sizeof(struct smb_acl) ||
end_of_acl < (char *)pdacl + le16_to_cpu(pdacl->size)) {
cifs_dbg(VFS, "ACL too small to parse DACL\n"); return;
}
/* We need DENY ACE when the perm is more restrictive than the next sets. */
deny_user_mode = ~(user_mode) & ((group_mode << 3) | (other_mode << 6)) & 0700;
deny_group_mode = ~(group_mode) & (other_mode << 3) & 0070;
/* Go through all the ACEs */ for (i = 0; i < src_num_aces; ++i) {
pntace = (struct smb_ace *) (acl_base + size);
pnntace = (struct smb_ace *) (nacl_base + nsize);
/* Assuming that pndacl and pnmode are never NULL */
nacl_base = (char *)pndacl;
nsize = sizeof(struct smb_acl);
/* If pdacl is NULL, we don't have a src. Simply populate new ACL. */ if (!pdacl || posix) {
populate_new_aces(nacl_base,
pownersid, pgrpsid,
pnmode, &num_aces, &nsize,
mode_from_sid, posix); goto finalize_dacl;
}
/* Retain old ACEs which we can retain */ for (i = 0; i < src_num_aces; ++i) {
pntace = (struct smb_ace *) (acl_base + size);
if (!new_aces_set && (pntace->flags & INHERITED_ACE)) { /* Place the new ACEs in between existing explicit and inherited */
populate_new_aces(nacl_base,
pownersid, pgrpsid,
pnmode, &num_aces, &nsize,
mode_from_sid, posix);
new_aces_set = true;
}
/* If it's any one of the ACE we're replacing, skip! */ if (((compare_sids(&pntace->sid, &sid_unix_NFS_mode) == 0) ||
(compare_sids(&pntace->sid, pownersid) == 0) ||
(compare_sids(&pntace->sid, pgrpsid) == 0) ||
(compare_sids(&pntace->sid, &sid_everyone) == 0) ||
(compare_sids(&pntace->sid, &sid_authusers) == 0))) { goto next_ace;
}
/* update the pointer to the next ACE to populate*/
pnntace = (struct smb_ace *) (nacl_base + nsize);
/* If inherited ACEs are not present, place the new ones at the tail */ if (!new_aces_set) {
populate_new_aces(nacl_base,
pownersid, pgrpsid,
pnmode, &num_aces, &nsize,
mode_from_sid, posix);
staticint parse_sid(struct smb_sid *psid, char *end_of_acl)
{ /* BB need to add parm so we can store the SID BB */
/* validate that we do not go past end of ACL - sid must be at least 8
bytes long (assuming no sub-auths - e.g. the null SID */ if (end_of_acl < (char *)psid + 8) {
cifs_dbg(VFS, "ACL too small to parse SID %p\n", psid); return -EINVAL;
}
#ifdef CONFIG_CIFS_DEBUG2 if (psid->num_subauth) { int i;
cifs_dbg(FYI, "SID revision %d num_auth %d\n",
psid->revision, psid->num_subauth);
for (i = 0; i < psid->num_subauth; i++) {
cifs_dbg(FYI, "SID sub_auth[%d]: 0x%x\n",
i, le32_to_cpu(psid->sub_auth[i]));
}
/* BB add length check to make sure that we do not have huge
num auths and therefore go off the end */
cifs_dbg(FYI, "RID 0x%x\n",
le32_to_cpu(psid->sub_auth[psid->num_subauth-1]));
} #endif
return0;
}
/* Convert CIFS ACL to POSIX form */ staticint parse_sec_desc(struct cifs_sb_info *cifs_sb, struct smb_ntsd *pntsd, int acl_len, struct cifs_fattr *fattr, bool get_mode_from_special_sid)
{ int rc = 0; struct smb_sid *owner_sid_ptr, *group_sid_ptr; struct smb_acl *dacl_ptr; /* no need for SACL ptr */ char *end_of_acl = ((char *)pntsd) + acl_len;
__u32 dacloffset;
rc = parse_sid(group_sid_ptr, end_of_acl); if (rc) {
cifs_dbg(FYI, "%s: Error %d mapping Owner SID to gid\n",
__func__, rc); return rc;
}
rc = sid_to_id(cifs_sb, group_sid_ptr, fattr, SIDGROUP); if (rc) {
cifs_dbg(FYI, "%s: Error %d mapping Group SID to gid\n",
__func__, rc); return rc;
}
if (dacloffset)
parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr,
group_sid_ptr, fattr, get_mode_from_special_sid); else
cifs_dbg(FYI, "no ACL\n"); /* BB grant all or default perms? */
return rc;
}
/* Convert permission bits from mode to equivalent CIFS ACL */ staticint build_sec_desc(struct smb_ntsd *pntsd, struct smb_ntsd *pnntsd,
__u32 secdesclen, __u32 *pnsecdesclen, __u64 *pnmode, kuid_t uid, kgid_t gid, bool mode_from_sid, bool id_from_sid, bool posix, int *aclflag)
{ int rc = 0;
__u32 dacloffset;
__u32 ndacloffset;
__u32 sidsoffset; struct smb_sid *owner_sid_ptr, *group_sid_ptr; struct smb_sid *nowner_sid_ptr = NULL, *ngroup_sid_ptr = NULL; struct smb_acl *dacl_ptr = NULL; /* no need for SACL ptr */ struct smb_acl *ndacl_ptr = NULL; /* no need for SACL ptr */ char *end_of_acl = ((char *)pntsd) + secdesclen;
u16 size = 0;
} else { /* lookup sid with upcall */
rc = id_to_sid(id, SIDOWNER, nowner_sid_ptr); if (rc) {
cifs_dbg(FYI, "%s: Mapping error %d for owner id %d\n",
__func__, rc, id); goto chown_chgrp_exit;
}
}
*aclflag |= CIFS_ACL_OWNER;
} if (gid_valid(gid)) { /* chgrp */
gid_t id;
ngroup_sid_ptr = kzalloc(sizeof(struct smb_sid),
GFP_KERNEL); if (!ngroup_sid_ptr) {
rc = -ENOMEM; goto chown_chgrp_exit;
}
id = from_kgid(&init_user_ns, gid); if (id_from_sid) { struct owner_sid *gsid = (struct owner_sid *)ngroup_sid_ptr; /* Populate the group ownership fields S-1-5-88-2 */
gsid->Revision = 1;
gsid->NumAuth = 3;
gsid->Authority[5] = 5;
gsid->SubAuthorities[0] = cpu_to_le32(88);
gsid->SubAuthorities[1] = cpu_to_le32(2);
gsid->SubAuthorities[2] = cpu_to_le32(id);
} else { /* lookup sid with upcall */
rc = id_to_sid(id, SIDGROUP, ngroup_sid_ptr); if (rc) {
cifs_dbg(FYI, "%s: Mapping error %d for group id %d\n",
__func__, rc, id); goto chown_chgrp_exit;
}
}
*aclflag |= CIFS_ACL_GROUP;
}
if (dacloffset) { /* Replace ACEs for old owner with new one */
size = replace_sids_and_copy_aces(dacl_ptr, ndacl_ptr,
owner_sid_ptr, group_sid_ptr,
nowner_sid_ptr, ngroup_sid_ptr);
ndacl_ptr->size = cpu_to_le16(size);
}
sidsoffset = ndacloffset + le16_to_cpu(ndacl_ptr->size); /* copy the non-dacl portion of secdesc */
*pnsecdesclen = copy_sec_desc(pntsd, pnntsd, sidsoffset,
nowner_sid_ptr, ngroup_sid_ptr);
chown_chgrp_exit: /* errors could jump here. So make sure we return soon after this */
kfree(nowner_sid_ptr);
kfree(ngroup_sid_ptr);
}
/* Translate the CIFS ACL (similar to NTFS ACL) for a file into mode bits */ int
cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr, struct inode *inode, bool mode_from_special_sid, constchar *path, conststruct cifs_fid *pfid)
{ struct smb_ntsd *pntsd = NULL;
u32 acllen = 0; int rc = 0; struct tcon_link *tlink = cifs_sb_tlink(cifs_sb); struct smb_version_operations *ops; const u32 info = OWNER_SECINFO | GROUP_SECINFO | DACL_SECINFO;
cifs_dbg(NOISY, "converting ACL to mode for %s\n", path);
if (IS_ERR(tlink)) return PTR_ERR(tlink);
ops = tlink_tcon(tlink)->ses->server->ops;
if (pfid && (ops->get_acl_by_fid))
pntsd = ops->get_acl_by_fid(cifs_sb, pfid, &acllen, info); elseif (ops->get_acl)
pntsd = ops->get_acl(cifs_sb, inode, path, &acllen, info); else {
cifs_put_tlink(tlink); return -EOPNOTSUPP;
} /* if we can retrieve the ACL, now parse Access Control Entries, ACEs */ if (IS_ERR(pntsd)) {
rc = PTR_ERR(pntsd);
cifs_dbg(VFS, "%s: error %d getting sec desc\n", __func__, rc);
} elseif (mode_from_special_sid) {
rc = parse_sec_desc(cifs_sb, pntsd, acllen, fattr, true);
kfree(pntsd);
} else { /* get approximated mode from ACL */
rc = parse_sec_desc(cifs_sb, pntsd, acllen, fattr, false);
kfree(pntsd); if (rc)
cifs_dbg(VFS, "parse sec desc failed rc = %d\n", rc);
}
cifs_put_tlink(tlink);
return rc;
}
/* Convert mode bits to an ACL so we can update the ACL on the server */ int
id_mode_to_cifs_acl(struct inode *inode, constchar *path, __u64 *pnmode,
kuid_t uid, kgid_t gid)
{ int rc = 0; int aclflag = CIFS_ACL_DACL; /* default flag to set */
__u32 secdesclen = 0;
__u32 nsecdesclen = 0;
__u32 dacloffset = 0; struct smb_acl *dacl_ptr = NULL; struct smb_ntsd *pntsd = NULL; /* acl obtained from server */ struct smb_ntsd *pnntsd = NULL; /* modified acl to be sent to server */ struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); struct tcon_link *tlink; struct smb_version_operations *ops; bool mode_from_sid, id_from_sid; const u32 info = OWNER_SECINFO | GROUP_SECINFO | DACL_SECINFO; bool posix;
tlink = cifs_sb_tlink(cifs_sb); if (IS_ERR(tlink)) return PTR_ERR(tlink);
posix = tlink_tcon(tlink)->posix_extensions;
ops = tlink_tcon(tlink)->ses->server->ops;
cifs_dbg(NOISY, "set ACL from mode for %s\n", path);
/* Get the security descriptor */
if (ops->get_acl == NULL) {
cifs_put_tlink(tlink); return -EOPNOTSUPP;
}
/* return alt name if available as pseudo attr */ switch (type) { case ACL_TYPE_ACCESS: if (sb->s_flags & SB_POSIXACL)
rc = cifs_do_get_acl(xid, pTcon, full_path, &acl,
ACL_TYPE_ACCESS,
cifs_sb->local_nls,
cifs_remap(cifs_sb)); break;
case ACL_TYPE_DEFAULT: if (sb->s_flags & SB_POSIXACL)
rc = cifs_do_get_acl(xid, pTcon, full_path, &acl,
ACL_TYPE_DEFAULT,
cifs_sb->local_nls,
cifs_remap(cifs_sb)); break;
}
if (rc < 0) { if (rc == -EINVAL)
acl = ERR_PTR(-EOPNOTSUPP); else
acl = ERR_PTR(rc);
}
/* return dos attributes as pseudo xattr */ /* return alt name if available as pseudo attr */
/* if proc/fs/cifs/streamstoxattr is set then searchserverforEAsorstreamsto
returns as xattrs */ if (posix_acl_xattr_size(acl->a_count) > CIFSMaxBufSize) {
cifs_dbg(FYI, "size of EA value too large\n");
rc = -EOPNOTSUPP; goto out;
}
switch (type) { case ACL_TYPE_ACCESS: if (sb->s_flags & SB_POSIXACL)
rc = cifs_do_set_acl(xid, pTcon, full_path, acl,
ACL_TYPE_ACCESS,
cifs_sb->local_nls,
cifs_remap(cifs_sb)); break;
case ACL_TYPE_DEFAULT: if (sb->s_flags & SB_POSIXACL)
rc = cifs_do_set_acl(xid, pTcon, full_path, acl,
ACL_TYPE_DEFAULT,
cifs_sb->local_nls,
cifs_remap(cifs_sb)); break;
}
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.38Bemerkung:
(vorverarbeitet am 2026-09-30)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.