Example #1
0
/* copy ntsd, owner sid, and group sid from a security descriptor to another */
static void copy_sec_desc(const struct cifs_ntsd *pntsd,
				struct cifs_ntsd *pnntsd, __u32 sidsoffset)
{
	struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
	struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr;

	/* copy security descriptor control portion */
	pnntsd->revision = pntsd->revision;
	pnntsd->type = pntsd->type;
	pnntsd->dacloffset = cpu_to_le32(sizeof(struct cifs_ntsd));
	pnntsd->sacloffset = 0;
	pnntsd->osidoffset = cpu_to_le32(sidsoffset);
	pnntsd->gsidoffset = cpu_to_le32(sidsoffset + sizeof(struct cifs_sid));

	/* copy owner sid */
	owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
				le32_to_cpu(pntsd->osidoffset));
	nowner_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset);
	cifs_copy_sid(nowner_sid_ptr, owner_sid_ptr);

	/* copy group sid */
	group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
				le32_to_cpu(pntsd->gsidoffset));
	ngroup_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset +
					sizeof(struct cifs_sid));
	cifs_copy_sid(ngroup_sid_ptr, group_sid_ptr);

	return;
}
Example #2
0
static int
id_to_sid(unsigned int cid, uint sidtype, struct cifs_sid *ssid)
{
	int rc;
	struct key *sidkey;
	struct cifs_sid *ksid;
	unsigned int ksid_size;
	char desc[3 + 10 + 1]; /* 3 byte prefix + 10 bytes for value + NULL */
	const struct cred *saved_cred;

	rc = snprintf(desc, sizeof(desc), "%ci:%u",
			sidtype == SIDOWNER ? 'o' : 'g', cid);
	if (rc >= sizeof(desc))
		return -EINVAL;

	rc = 0;
	saved_cred = override_creds(root_cred);
	sidkey = request_key(&cifs_idmap_key_type, desc, "");
	if (IS_ERR(sidkey)) {
		rc = -EINVAL;
		cifs_dbg(FYI, "%s: Can't map %cid %u to a SID\n",
			 __func__, sidtype == SIDOWNER ? 'u' : 'g', cid);
		goto out_revert_creds;
	} else if (sidkey->datalen < CIFS_SID_BASE_SIZE) {
		rc = -EIO;
		cifs_dbg(FYI, "%s: Downcall contained malformed key (datalen=%hu)\n",
			 __func__, sidkey->datalen);
		goto invalidate_key;
	}

	/*
	 * A sid is usually too large to be embedded in payload.value, but if
	 * there are no subauthorities and the host has 8-byte pointers, then
	 * it could be.
	 */
	ksid = sidkey->datalen <= sizeof(sidkey->payload) ?
		(struct cifs_sid *)&sidkey->payload :
		(struct cifs_sid *)sidkey->payload.data[0];

	ksid_size = CIFS_SID_BASE_SIZE + (ksid->num_subauth * sizeof(__le32));
	if (ksid_size > sidkey->datalen) {
		rc = -EIO;
		cifs_dbg(FYI, "%s: Downcall contained malformed key (datalen=%hu, ksid_size=%u)\n",
			 __func__, sidkey->datalen, ksid_size);
		goto invalidate_key;
	}

	cifs_copy_sid(ssid, ksid);
out_key_put:
	key_put(sidkey);
out_revert_creds:
	revert_creds(saved_cred);
	return rc;

invalidate_key:
	key_invalidate(sidkey);
	goto out_key_put;
}
static void
id_rb_insert(struct rb_root *root, struct cifs_sid *sidptr,
             struct cifs_sid_id **psidid, char *typestr)
{
    int rc;
    char *strptr;
    struct rb_node *node = root->rb_node;
    struct rb_node *parent = NULL;
    struct rb_node **linkto = &(root->rb_node);
    struct cifs_sid_id *lsidid;

    while (node) {
        lsidid = rb_entry(node, struct cifs_sid_id, rbnode);
        parent = node;
        rc = compare_sids(sidptr, &((lsidid)->sid));
        if (rc > 0) {
            linkto = &(node->rb_left);
            node = node->rb_left;
        } else if (rc < 0) {
            linkto = &(node->rb_right);
            node = node->rb_right;
        }
    }

    cifs_copy_sid(&(*psidid)->sid, sidptr);
    (*psidid)->time = jiffies - (SID_MAP_RETRY + 1);
    (*psidid)->refcount = 0;

    sprintf((*psidid)->sidstr, "%s", typestr);
    strptr = (*psidid)->sidstr + strlen((*psidid)->sidstr);
    sid_to_str(&(*psidid)->sid, strptr);

    clear_bit(SID_ID_PENDING, &(*psidid)->state);
    clear_bit(SID_ID_MAPPED, &(*psidid)->state);

    rb_link_node(&(*psidid)->rbnode, parent, linkto);
    rb_insert_color(&(*psidid)->rbnode, root);
}
Example #4
0
/* Convert permission bits from mode to equivalent CIFS ACL */
static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
	__u32 secdesclen, __u64 nmode, kuid_t uid, kgid_t gid, int *aclflag)
{
	int rc = 0;
	__u32 dacloffset;
	__u32 ndacloffset;
	__u32 sidsoffset;
	struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
	struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr;
	struct cifs_acl *dacl_ptr = NULL;  /* no need for SACL ptr */
	struct cifs_acl *ndacl_ptr = NULL; /* no need for SACL ptr */

	if (nmode != NO_CHANGE_64) { /* chmod */
		owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
				le32_to_cpu(pntsd->osidoffset));
		group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
				le32_to_cpu(pntsd->gsidoffset));
		dacloffset = le32_to_cpu(pntsd->dacloffset);
		dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
		ndacloffset = sizeof(struct cifs_ntsd);
		ndacl_ptr = (struct cifs_acl *)((char *)pnntsd + ndacloffset);
		ndacl_ptr->revision = dacl_ptr->revision;
		ndacl_ptr->size = 0;
		ndacl_ptr->num_aces = 0;

		rc = set_chmod_dacl(ndacl_ptr, owner_sid_ptr, group_sid_ptr,
					nmode);
		sidsoffset = ndacloffset + le16_to_cpu(ndacl_ptr->size);
		/* copy sec desc control portion & owner and group sids */
		copy_sec_desc(pntsd, pnntsd, sidsoffset);
		*aclflag = CIFS_ACL_DACL;
	} else {
		memcpy(pnntsd, pntsd, secdesclen);
		if (uid_valid(uid)) { /* chown */
			uid_t id;
			owner_sid_ptr = (struct cifs_sid *)((char *)pnntsd +
					le32_to_cpu(pnntsd->osidoffset));
			nowner_sid_ptr = kmalloc(sizeof(struct cifs_sid),
								GFP_KERNEL);
			if (!nowner_sid_ptr)
				return -ENOMEM;
			id = from_kuid(&init_user_ns, uid);
			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);
				kfree(nowner_sid_ptr);
				return rc;
			}
			cifs_copy_sid(owner_sid_ptr, nowner_sid_ptr);
			kfree(nowner_sid_ptr);
			*aclflag = CIFS_ACL_OWNER;
		}
		if (gid_valid(gid)) { /* chgrp */
			gid_t id;
			group_sid_ptr = (struct cifs_sid *)((char *)pnntsd +
					le32_to_cpu(pnntsd->gsidoffset));
			ngroup_sid_ptr = kmalloc(sizeof(struct cifs_sid),
								GFP_KERNEL);
			if (!ngroup_sid_ptr)
				return -ENOMEM;
			id = from_kgid(&init_user_ns, gid);
			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);
				kfree(ngroup_sid_ptr);
				return rc;
			}
			cifs_copy_sid(group_sid_ptr, ngroup_sid_ptr);
			kfree(ngroup_sid_ptr);
			*aclflag = CIFS_ACL_GROUP;
		}
	}

	return rc;
}
static int
id_to_sid(unsigned long cid, uint sidtype, struct cifs_sid *ssid)
{
    int rc = 0;
    struct key *sidkey;
    const struct cred *saved_cred;
    struct cifs_sid *lsid;
    struct cifs_sid_id *psidid, *npsidid;
    struct rb_root *cidtree;
    spinlock_t *cidlock;

    if (sidtype == SIDOWNER) {
        cidlock = &siduidlock;
        cidtree = &uidtree;
    } else if (sidtype == SIDGROUP) {
        cidlock = &sidgidlock;
        cidtree = &gidtree;
    } else
        return -EINVAL;

    spin_lock(cidlock);
    psidid = sid_rb_search(cidtree, cid);

    if (!psidid) { /* node does not exist, allocate one & attempt adding */
        spin_unlock(cidlock);
        npsidid = kzalloc(sizeof(struct cifs_sid_id), GFP_KERNEL);
        if (!npsidid)
            return -ENOMEM;

        npsidid->sidstr = kmalloc(SIDLEN, GFP_KERNEL);
        if (!npsidid->sidstr) {
            kfree(npsidid);
            return -ENOMEM;
        }

        spin_lock(cidlock);
        psidid = sid_rb_search(cidtree, cid);
        if (psidid) { /* node happened to get inserted meanwhile */
            ++psidid->refcount;
            spin_unlock(cidlock);
            kfree(npsidid->sidstr);
            kfree(npsidid);
        } else {
            psidid = npsidid;
            sid_rb_insert(cidtree, cid, &psidid,
                          sidtype == SIDOWNER ? "oi:" : "gi:");
            ++psidid->refcount;
            spin_unlock(cidlock);
        }
    } else {
        ++psidid->refcount;
        spin_unlock(cidlock);
    }

    /*
     * If we are here, it is safe to access psidid and its fields
     * since a reference was taken earlier while holding the spinlock.
     * A reference on the node is put without holding the spinlock
     * and it is OK to do so in this case, shrinker will not erase
     * this node until all references are put and we do not access
     * any fields of the node after a reference is put .
     */
    if (test_bit(SID_ID_MAPPED, &psidid->state)) {
        cifs_copy_sid(ssid, &psidid->sid);
        psidid->time = jiffies; /* update ts for accessing */
        goto id_sid_out;
    }

    if (time_after(psidid->time + SID_MAP_RETRY, jiffies)) {
        rc = -EINVAL;
        goto id_sid_out;
    }

    if (!test_and_set_bit(SID_ID_PENDING, &psidid->state)) {
        saved_cred = override_creds(root_cred);
        sidkey = request_key(&cifs_idmap_key_type, psidid->sidstr, "");
        if (IS_ERR(sidkey)) {
            rc = -EINVAL;
            cFYI(1, "%s: Can't map and id to a SID", __func__);
        } else if (sidkey->datalen < sizeof(struct cifs_sid)) {
            rc = -EIO;
            cFYI(1, "%s: Downcall contained malformed key "
                 "(datalen=%hu)", __func__, sidkey->datalen);
        } else {
            lsid = (struct cifs_sid *)sidkey->payload.data;
            cifs_copy_sid(&psidid->sid, lsid);
            cifs_copy_sid(ssid, &psidid->sid);
            set_bit(SID_ID_MAPPED, &psidid->state);
            key_put(sidkey);
            kfree(psidid->sidstr);
        }
        psidid->time = jiffies; /* update ts for accessing */
        revert_creds(saved_cred);
        clear_bit(SID_ID_PENDING, &psidid->state);
        wake_up_bit(&psidid->state, SID_ID_PENDING);
    } else {
        rc = wait_on_bit(&psidid->state, SID_ID_PENDING,
                         sidid_pending_wait, TASK_INTERRUPTIBLE);
        if (rc) {
            cFYI(1, "%s: sidid_pending_wait interrupted %d",
                 __func__, rc);
            --psidid->refcount;
            return rc;
        }
        if (test_bit(SID_ID_MAPPED, &psidid->state))
            cifs_copy_sid(ssid, &psidid->sid);
        else
            rc = -EINVAL;
    }
id_sid_out:
    --psidid->refcount;
    return rc;
}