[PATCH] keys: let keyctl_chown() change a key's owner
Let keyctl_chown() change a key's owner, including attempting to transfer the quota burden to the new user. Signed-off-by: David Howells <dhowells@redhat.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
This commit is contained in:
Родитель
31204ed925
Коммит
5801649d8b
|
@ -673,6 +673,7 @@ long keyctl_read_key(key_serial_t keyid, char __user *buffer, size_t buflen)
|
|||
*/
|
||||
long keyctl_chown_key(key_serial_t id, uid_t uid, gid_t gid)
|
||||
{
|
||||
struct key_user *newowner, *zapowner = NULL;
|
||||
struct key *key;
|
||||
key_ref_t key_ref;
|
||||
long ret;
|
||||
|
@ -696,19 +697,50 @@ long keyctl_chown_key(key_serial_t id, uid_t uid, gid_t gid)
|
|||
if (!capable(CAP_SYS_ADMIN)) {
|
||||
/* only the sysadmin can chown a key to some other UID */
|
||||
if (uid != (uid_t) -1 && key->uid != uid)
|
||||
goto no_access;
|
||||
goto error_put;
|
||||
|
||||
/* only the sysadmin can set the key's GID to a group other
|
||||
* than one of those that the current process subscribes to */
|
||||
if (gid != (gid_t) -1 && gid != key->gid && !in_group_p(gid))
|
||||
goto no_access;
|
||||
goto error_put;
|
||||
}
|
||||
|
||||
/* change the UID (have to update the quotas) */
|
||||
/* change the UID */
|
||||
if (uid != (uid_t) -1 && uid != key->uid) {
|
||||
/* don't support UID changing yet */
|
||||
ret = -EOPNOTSUPP;
|
||||
goto no_access;
|
||||
ret = -ENOMEM;
|
||||
newowner = key_user_lookup(uid);
|
||||
if (!newowner)
|
||||
goto error_put;
|
||||
|
||||
/* transfer the quota burden to the new user */
|
||||
if (test_bit(KEY_FLAG_IN_QUOTA, &key->flags)) {
|
||||
spin_lock(&newowner->lock);
|
||||
if (newowner->qnkeys + 1 >= KEYQUOTA_MAX_KEYS ||
|
||||
newowner->qnbytes + key->quotalen >=
|
||||
KEYQUOTA_MAX_BYTES)
|
||||
goto quota_overrun;
|
||||
|
||||
newowner->qnkeys++;
|
||||
newowner->qnbytes += key->quotalen;
|
||||
spin_unlock(&newowner->lock);
|
||||
|
||||
spin_lock(&key->user->lock);
|
||||
key->user->qnkeys--;
|
||||
key->user->qnbytes -= key->quotalen;
|
||||
spin_unlock(&key->user->lock);
|
||||
}
|
||||
|
||||
atomic_dec(&key->user->nkeys);
|
||||
atomic_inc(&newowner->nkeys);
|
||||
|
||||
if (test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) {
|
||||
atomic_dec(&key->user->nikeys);
|
||||
atomic_inc(&newowner->nikeys);
|
||||
}
|
||||
|
||||
zapowner = key->user;
|
||||
key->user = newowner;
|
||||
key->uid = uid;
|
||||
}
|
||||
|
||||
/* change the GID */
|
||||
|
@ -717,12 +749,20 @@ long keyctl_chown_key(key_serial_t id, uid_t uid, gid_t gid)
|
|||
|
||||
ret = 0;
|
||||
|
||||
no_access:
|
||||
error_put:
|
||||
up_write(&key->sem);
|
||||
key_put(key);
|
||||
error:
|
||||
if (zapowner)
|
||||
key_user_put(zapowner);
|
||||
error:
|
||||
return ret;
|
||||
|
||||
quota_overrun:
|
||||
spin_unlock(&newowner->lock);
|
||||
zapowner = newowner;
|
||||
ret = -EDQUOT;
|
||||
goto error_put;
|
||||
|
||||
} /* end keyctl_chown_key() */
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
Загрузка…
Ссылка в новой задаче