⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 keyctl.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
			ret = -ENOKEY;		goto error5;	}	/* link the resulting key to the destination keyring if we can */	if (dest_ref) {		ret = key_permission(key_ref, KEY_LINK);		if (ret < 0)			goto error6;		ret = key_link(key_ref_to_ptr(dest_ref), key_ref_to_ptr(key_ref));		if (ret < 0)			goto error6;	}	ret = key_ref_to_ptr(key_ref)->serial; error6:	key_ref_put(key_ref); error5:	key_type_put(ktype); error4:	key_ref_put(dest_ref); error3:	key_ref_put(keyring_ref); error2:	kfree(description); error:	return ret;} /* end keyctl_keyring_search() *//*****************************************************************************//* * read a user key's payload * - the keyring must be readable or the key must be searchable from the *   process's keyrings * - if there's a buffer, we place up to buflen bytes of data into it * - unless there's an error, we return the amount of data in the key, *   irrespective of how much we may have copied * - implements keyctl(KEYCTL_READ) */long keyctl_read_key(key_serial_t keyid, char __user *buffer, size_t buflen){	struct key *key;	key_ref_t key_ref;	long ret;	/* find the key first */	key_ref = lookup_user_key(NULL, keyid, 0, 0, 0);	if (IS_ERR(key_ref)) {		ret = -ENOKEY;		goto error;	}	key = key_ref_to_ptr(key_ref);	/* see if we can read it directly */	ret = key_permission(key_ref, KEY_READ);	if (ret == 0)		goto can_read_key;	if (ret != -EACCES)		goto error;	/* we can't; see if it's searchable from this process's keyrings	 * - we automatically take account of the fact that it may be	 *   dangling off an instantiation key	 */	if (!is_key_possessed(key_ref)) {		ret = -EACCES;		goto error2;	}	/* the key is probably readable - now try to read it */ can_read_key:	ret = key_validate(key);	if (ret == 0) {		ret = -EOPNOTSUPP;		if (key->type->read) {			/* read the data with the semaphore held (since we			 * might sleep) */			down_read(&key->sem);			ret = key->type->read(key, buffer, buflen);			up_read(&key->sem);		}	} error2:	key_put(key); error:	return ret;} /* end keyctl_read_key() *//*****************************************************************************//* * change the ownership of a key * - the keyring owned by the changer * - if the uid or gid is -1, then that parameter is not changed * - implements keyctl(KEYCTL_CHOWN) */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;	ret = 0;	if (uid == (uid_t) -1 && gid == (gid_t) -1)		goto error;	key_ref = lookup_user_key(NULL, id, 1, 1, KEY_SETATTR);	if (IS_ERR(key_ref)) {		ret = PTR_ERR(key_ref);		goto error;	}	key = key_ref_to_ptr(key_ref);	/* make the changes with the locks held to prevent chown/chown races */	ret = -EACCES;	down_write(&key->sem);	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 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 error_put;	}	/* change the UID */	if (uid != (uid_t) -1 && uid != key->uid) {		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 */	if (gid != (gid_t) -1)		key->gid = gid;	ret = 0;error_put:	up_write(&key->sem);	key_put(key);	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() *//*****************************************************************************//* * change the permission mask on a key * - the keyring owned by the changer * - implements keyctl(KEYCTL_SETPERM) */long keyctl_setperm_key(key_serial_t id, key_perm_t perm){	struct key *key;	key_ref_t key_ref;	long ret;	ret = -EINVAL;	if (perm & ~(KEY_POS_ALL | KEY_USR_ALL | KEY_GRP_ALL | KEY_OTH_ALL))		goto error;	key_ref = lookup_user_key(NULL, id, 1, 1, KEY_SETATTR);	if (IS_ERR(key_ref)) {		ret = PTR_ERR(key_ref);		goto error;	}	key = key_ref_to_ptr(key_ref);	/* make the changes with the locks held to prevent chown/chmod races */	ret = -EACCES;	down_write(&key->sem);	/* if we're not the sysadmin, we can only change a key that we own */	if (capable(CAP_SYS_ADMIN) || key->uid == current->fsuid) {		key->perm = perm;		ret = 0;	}	up_write(&key->sem);	key_put(key);error:	return ret;} /* end keyctl_setperm_key() *//*****************************************************************************//* * instantiate the key with the specified payload, and, if one is given, link * the key into the keyring */long keyctl_instantiate_key(key_serial_t id,			    const void __user *_payload,			    size_t plen,			    key_serial_t ringid){	struct request_key_auth *rka;	struct key *instkey;	key_ref_t keyring_ref;	void *payload;	long ret;	ret = -EINVAL;	if (plen > 32767)		goto error;	/* the appropriate instantiation authorisation key must have been	 * assumed before calling this */	ret = -EPERM;	instkey = current->request_key_auth;	if (!instkey)		goto error;	rka = instkey->payload.data;	if (rka->target_key->serial != id)		goto error;	/* pull the payload in if one was supplied */	payload = NULL;	if (_payload) {		ret = -ENOMEM;		payload = kmalloc(plen, GFP_KERNEL);		if (!payload)			goto error;		ret = -EFAULT;		if (copy_from_user(payload, _payload, plen) != 0)			goto error2;	}	/* find the destination keyring amongst those belonging to the	 * requesting task */	keyring_ref = NULL;	if (ringid) {		keyring_ref = lookup_user_key(rka->context, ringid, 1, 0,					      KEY_WRITE);		if (IS_ERR(keyring_ref)) {			ret = PTR_ERR(keyring_ref);			goto error2;		}	}	/* instantiate the key and link it into a keyring */	ret = key_instantiate_and_link(rka->target_key, payload, plen,				       key_ref_to_ptr(keyring_ref), instkey);	key_ref_put(keyring_ref);	/* discard the assumed authority if it's just been disabled by	 * instantiation of the key */	if (ret == 0) {		key_put(current->request_key_auth);		current->request_key_auth = NULL;	}error2:	kfree(payload);error:	return ret;} /* end keyctl_instantiate_key() *//*****************************************************************************//* * negatively instantiate the key with the given timeout (in seconds), and, if * one is given, link the key into the keyring */long keyctl_negate_key(key_serial_t id, unsigned timeout, key_serial_t ringid){	struct request_key_auth *rka;	struct key *instkey;	key_ref_t keyring_ref;	long ret;	/* the appropriate instantiation authorisation key must have been	 * assumed before calling this */	ret = -EPERM;	instkey = current->request_key_auth;	if (!instkey)		goto error;	rka = instkey->payload.data;	if (rka->target_key->serial != id)		goto error;	/* find the destination keyring if present (which must also be	 * writable) */	keyring_ref = NULL;	if (ringid) {		keyring_ref = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE);		if (IS_ERR(keyring_ref)) {			ret = PTR_ERR(keyring_ref);			goto error;		}	}	/* instantiate the key and link it into a keyring */	ret = key_negate_and_link(rka->target_key, timeout,				  key_ref_to_ptr(keyring_ref), instkey);	key_ref_put(keyring_ref);	/* discard the assumed authority if it's just been disabled by	 * instantiation of the key */	if (ret == 0) {		key_put(current->request_key_auth);		current->request_key_auth = NULL;	}error:	return ret;} /* end keyctl_negate_key() *//*****************************************************************************//* * set the default keyring in which request_key() will cache keys * - return the old setting */long keyctl_set_reqkey_keyring(int reqkey_defl){	int ret;	switch (reqkey_defl) {	case KEY_REQKEY_DEFL_THREAD_KEYRING:		ret = install_thread_keyring(current);		if (ret < 0)			return ret;		goto set;	case KEY_REQKEY_DEFL_PROCESS_KEYRING:		ret = install_process_keyring(current);		if (ret < 0)			return ret;	case KEY_REQKEY_DEFL_DEFAULT:	case KEY_REQKEY_DEFL_SESSION_KEYRING:	case KEY_REQKEY_DEFL_USER_KEYRING:	case KEY_REQKEY_DEFL_USER_SESSION_KEYRING:	set:		current->jit_keyring = reqkey_defl;	case KEY_REQKEY_DEFL_NO_CHANGE:		return current->jit_keyring;	case KEY_REQKEY_DEFL_GROUP_KEYRING:	default:		return -EINVAL;	}} /* end keyctl_set_reqkey_keyring() *//*****************************************************************************//* * set or clear the timeout for a key */long keyctl_set_timeout(key_serial_t id, unsigned timeout){	struct timespec now;	struct key *key;	key_ref_t key_ref;	time_t expiry;	long ret;	key_ref = lookup_user_key(NULL, id, 1, 1, KEY_SETATTR);	if (IS_ERR(key_ref)) {		ret = PTR_ERR(key_ref);		goto error;	}	key = key_ref_to_ptr(key_ref);	/* make the changes with the locks held to prevent races */	down_write(&key->sem);	expiry = 0;	if (timeout > 0) {		now = current_kernel_time();		expiry = now.tv_sec + timeout;	}	key->expiry = expiry;	up_write(&key->sem);	key_put(key);	ret = 0;error:	return ret;} /* end keyctl_set_timeout() *//*****************************************************************************//* * assume the authority to instantiate the specified key */long keyctl_assume_authority(key_serial_t id){	struct key *authkey;	long ret;	/* special key IDs aren't permitted */	ret = -EINVAL;	if (id < 0)		goto error;	/* we divest ourselves of authority if given an ID of 0 */	if (id == 0) {		key_put(current->request_key_auth);		current->request_key_auth = NULL;		ret = 0;		goto error;	}	/* attempt to assume the authority temporarily granted to us whilst we	 * instantiate the specified key	 * - the authorisation key must be in the current task's keyrings	 *   somewhere	 */	authkey = key_get_instantiation_authkey(id);	if (IS_ERR(authkey)) {		ret = PTR_ERR(authkey);		goto error;	}	key_put(current->request_key_auth);	current->request_key_auth = authkey;	ret = authkey->serial;error:	return ret;} /* end keyctl_assume_authority() *//*****************************************************************************//* * the key control system call */asmlinkage long sys_keyctl(int option, unsigned long arg2, unsigned long arg3,			   unsigned long arg4, unsigned long arg5){	switch (option) {	case KEYCTL_GET_KEYRING_ID:		return keyctl_get_keyring_ID((key_serial_t) arg2,					     (int) arg3);	case KEYCTL_JOIN_SESSION_KEYRING:		return keyctl_join_session_keyring((const char __user *) arg2);	case KEYCTL_UPDATE:		return keyctl_update_key((key_serial_t) arg2,					 (const void __user *) arg3,					 (size_t) arg4);	case KEYCTL_REVOKE:		return keyctl_revoke_key((key_serial_t) arg2);	case KEYCTL_DESCRIBE:		return keyctl_describe_key((key_serial_t) arg2,					   (char __user *) arg3,					   (unsigned) arg4);	case KEYCTL_CLEAR:		return keyctl_keyring_clear((key_serial_t) arg2);	case KEYCTL_LINK:		return keyctl_keyring_link((key_serial_t) arg2,					   (key_serial_t) arg3);	case KEYCTL_UNLINK:		return keyctl_keyring_unlink((key_serial_t) arg2,					     (key_serial_t) arg3);	case KEYCTL_SEARCH:		return keyctl_keyring_search((key_serial_t) arg2,					     (const char __user *) arg3,					     (const char __user *) arg4,					     (key_serial_t) arg5);	case KEYCTL_READ:		return keyctl_read_key((key_serial_t) arg2,				       (char __user *) arg3,				       (size_t) arg4);	case KEYCTL_CHOWN:		return keyctl_chown_key((key_serial_t) arg2,					(uid_t) arg3,					(gid_t) arg4);	case KEYCTL_SETPERM:		return keyctl_setperm_key((key_serial_t) arg2,					  (key_perm_t) arg3);	case KEYCTL_INSTANTIATE:		return keyctl_instantiate_key((key_serial_t) arg2,					      (const void __user *) arg3,					      (size_t) arg4,					      (key_serial_t) arg5);	case KEYCTL_NEGATE:		return keyctl_negate_key((key_serial_t) arg2,					 (unsigned) arg3,					 (key_serial_t) arg4);	case KEYCTL_SET_REQKEY_KEYRING:		return keyctl_set_reqkey_keyring(arg2);	case KEYCTL_SET_TIMEOUT:		return keyctl_set_timeout((key_serial_t) arg2,					  (unsigned) arg3);	case KEYCTL_ASSUME_AUTHORITY:		return keyctl_assume_authority((key_serial_t) arg2);	default:		return -EOPNOTSUPP;	}} /* end sys_keyctl() */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -