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

📄 keyctl.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* keyctl.c: userspace keyctl operations * * Copyright (C) 2004-5 Red Hat, Inc. All Rights Reserved. * Written by David Howells (dhowells@redhat.com) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */#include <linux/module.h>#include <linux/init.h>#include <linux/sched.h>#include <linux/slab.h>#include <linux/syscalls.h>#include <linux/keyctl.h>#include <linux/fs.h>#include <linux/capability.h>#include <linux/string.h>#include <linux/err.h>#include <asm/uaccess.h>#include "internal.h"static int key_get_type_from_user(char *type,				  const char __user *_type,				  unsigned len){	int ret;	ret = strncpy_from_user(type, _type, len);	if (ret < 0)		return -EFAULT;	if (ret == 0 || ret >= len)		return -EINVAL;	if (type[0] == '.')		return -EPERM;	type[len - 1] = '\0';	return 0;}/*****************************************************************************//* * extract the description of a new key from userspace and either add it as a * new key to the specified keyring or update a matching key in that keyring * - the keyring must be writable * - returns the new key's serial number * - implements add_key() */asmlinkage long sys_add_key(const char __user *_type,			    const char __user *_description,			    const void __user *_payload,			    size_t plen,			    key_serial_t ringid){	key_ref_t keyring_ref, key_ref;	char type[32], *description;	void *payload;	long ret;	ret = -EINVAL;	if (plen > 32767)		goto error;	/* draw all the data into kernel space */	ret = key_get_type_from_user(type, _type, sizeof(type));	if (ret < 0)		goto error;	description = strndup_user(_description, PAGE_SIZE);	if (IS_ERR(description)) {		ret = PTR_ERR(description);		goto error;	}	/* pull the payload in if one was supplied */	payload = NULL;	if (_payload) {		ret = -ENOMEM;		payload = kmalloc(plen, GFP_KERNEL);		if (!payload)			goto error2;		ret = -EFAULT;		if (copy_from_user(payload, _payload, plen) != 0)			goto error3;	}	/* find the target keyring (which must be writable) */	keyring_ref = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE);	if (IS_ERR(keyring_ref)) {		ret = PTR_ERR(keyring_ref);		goto error3;	}	/* create or update the requested key and add it to the target	 * keyring */	key_ref = key_create_or_update(keyring_ref, type, description,				       payload, plen, KEY_ALLOC_IN_QUOTA);	if (!IS_ERR(key_ref)) {		ret = key_ref_to_ptr(key_ref)->serial;		key_ref_put(key_ref);	}	else {		ret = PTR_ERR(key_ref);	}	key_ref_put(keyring_ref); error3:	kfree(payload); error2:	kfree(description); error:	return ret;} /* end sys_add_key() *//*****************************************************************************//* * search the process keyrings for a matching key * - nested keyrings may also be searched if they have Search permission * - if a key is found, it will be attached to the destination keyring if *   there's one specified * - /sbin/request-key will be invoked if _callout_info is non-NULL *   - the _callout_info string will be passed to /sbin/request-key *   - if the _callout_info string is empty, it will be rendered as "-" * - implements request_key() */asmlinkage long sys_request_key(const char __user *_type,				const char __user *_description,				const char __user *_callout_info,				key_serial_t destringid){	struct key_type *ktype;	struct key *key;	key_ref_t dest_ref;	char type[32], *description, *callout_info;	long ret;	/* pull the type into kernel space */	ret = key_get_type_from_user(type, _type, sizeof(type));	if (ret < 0)		goto error;	/* pull the description into kernel space */	description = strndup_user(_description, PAGE_SIZE);	if (IS_ERR(description)) {		ret = PTR_ERR(description);		goto error;	}	/* pull the callout info into kernel space */	callout_info = NULL;	if (_callout_info) {		callout_info = strndup_user(_callout_info, PAGE_SIZE);		if (IS_ERR(callout_info)) {			ret = PTR_ERR(callout_info);			goto error2;		}	}	/* get the destination keyring if specified */	dest_ref = NULL;	if (destringid) {		dest_ref = lookup_user_key(NULL, destringid, 1, 0, KEY_WRITE);		if (IS_ERR(dest_ref)) {			ret = PTR_ERR(dest_ref);			goto error3;		}	}	/* find the key type */	ktype = key_type_lookup(type);	if (IS_ERR(ktype)) {		ret = PTR_ERR(ktype);		goto error4;	}	/* do the search */	key = request_key_and_link(ktype, description, callout_info, NULL,				   key_ref_to_ptr(dest_ref),				   KEY_ALLOC_IN_QUOTA);	if (IS_ERR(key)) {		ret = PTR_ERR(key);		goto error5;	}	ret = key->serial; 	key_put(key); error5:	key_type_put(ktype); error4:	key_ref_put(dest_ref); error3:	kfree(callout_info); error2:	kfree(description); error:	return ret;} /* end sys_request_key() *//*****************************************************************************//* * get the ID of the specified process keyring * - the keyring must have search permission to be found * - implements keyctl(KEYCTL_GET_KEYRING_ID) */long keyctl_get_keyring_ID(key_serial_t id, int create){	key_ref_t key_ref;	long ret;	key_ref = lookup_user_key(NULL, id, create, 0, KEY_SEARCH);	if (IS_ERR(key_ref)) {		ret = PTR_ERR(key_ref);		goto error;	}	ret = key_ref_to_ptr(key_ref)->serial;	key_ref_put(key_ref); error:	return ret;} /* end keyctl_get_keyring_ID() *//*****************************************************************************//* * join the session keyring * - implements keyctl(KEYCTL_JOIN_SESSION_KEYRING) */long keyctl_join_session_keyring(const char __user *_name){	char *name;	long ret;	/* fetch the name from userspace */	name = NULL;	if (_name) {		name = strndup_user(_name, PAGE_SIZE);		if (IS_ERR(name)) {			ret = PTR_ERR(name);			goto error;		}	}	/* join the session */	ret = join_session_keyring(name); error:	return ret;} /* end keyctl_join_session_keyring() *//*****************************************************************************//* * update a key's data payload * - the key must be writable * - implements keyctl(KEYCTL_UPDATE) */long keyctl_update_key(key_serial_t id,		       const void __user *_payload,		       size_t plen){	key_ref_t key_ref;	void *payload;	long ret;	ret = -EINVAL;	if (plen > PAGE_SIZE)		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 target key (which must be writable) */	key_ref = lookup_user_key(NULL, id, 0, 0, KEY_WRITE);	if (IS_ERR(key_ref)) {		ret = PTR_ERR(key_ref);		goto error2;	}	/* update the key */	ret = key_update(key_ref, payload, plen);	key_ref_put(key_ref); error2:	kfree(payload); error:	return ret;} /* end keyctl_update_key() *//*****************************************************************************//* * revoke a key * - the key must be writable * - implements keyctl(KEYCTL_REVOKE) */long keyctl_revoke_key(key_serial_t id){	key_ref_t key_ref;	long ret;	key_ref = lookup_user_key(NULL, id, 0, 0, KEY_WRITE);	if (IS_ERR(key_ref)) {		ret = PTR_ERR(key_ref);		goto error;	}	key_revoke(key_ref_to_ptr(key_ref));	ret = 0;	key_ref_put(key_ref); error:	return ret;} /* end keyctl_revoke_key() *//*****************************************************************************//* * clear the specified process keyring * - the keyring must be writable * - implements keyctl(KEYCTL_CLEAR) */long keyctl_keyring_clear(key_serial_t ringid){	key_ref_t keyring_ref;	long ret;	keyring_ref = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE);	if (IS_ERR(keyring_ref)) {		ret = PTR_ERR(keyring_ref);		goto error;	}	ret = keyring_clear(key_ref_to_ptr(keyring_ref));	key_ref_put(keyring_ref); error:	return ret;} /* end keyctl_keyring_clear() *//*****************************************************************************//* * link a key into a keyring * - the keyring must be writable * - the key must be linkable * - implements keyctl(KEYCTL_LINK) */long keyctl_keyring_link(key_serial_t id, key_serial_t ringid){	key_ref_t keyring_ref, key_ref;	long ret;	keyring_ref = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE);	if (IS_ERR(keyring_ref)) {		ret = PTR_ERR(keyring_ref);		goto error;	}	key_ref = lookup_user_key(NULL, id, 1, 0, KEY_LINK);	if (IS_ERR(key_ref)) {		ret = PTR_ERR(key_ref);		goto error2;	}	ret = key_link(key_ref_to_ptr(keyring_ref), key_ref_to_ptr(key_ref));	key_ref_put(key_ref); error2:	key_ref_put(keyring_ref); error:	return ret;} /* end keyctl_keyring_link() *//*****************************************************************************//* * unlink the first attachment of a key from a keyring * - the keyring must be writable * - we don't need any permissions on the key * - implements keyctl(KEYCTL_UNLINK) */long keyctl_keyring_unlink(key_serial_t id, key_serial_t ringid){	key_ref_t keyring_ref, key_ref;	long ret;	keyring_ref = lookup_user_key(NULL, ringid, 0, 0, KEY_WRITE);	if (IS_ERR(keyring_ref)) {		ret = PTR_ERR(keyring_ref);		goto error;	}	key_ref = lookup_user_key(NULL, id, 0, 0, 0);	if (IS_ERR(key_ref)) {		ret = PTR_ERR(key_ref);		goto error2;	}	ret = key_unlink(key_ref_to_ptr(keyring_ref), key_ref_to_ptr(key_ref));	key_ref_put(key_ref); error2:	key_ref_put(keyring_ref); error:	return ret;} /* end keyctl_keyring_unlink() *//*****************************************************************************//* * describe a user key * - the key must have view permission * - 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 description available, *   irrespective of how much we may have copied * - the description is formatted thus: *	type;uid;gid;perm;description<NUL> * - implements keyctl(KEYCTL_DESCRIBE) */long keyctl_describe_key(key_serial_t keyid,			 char __user *buffer,			 size_t buflen){	struct key *key, *instkey;	key_ref_t key_ref;	char *tmpbuf;	long ret;	key_ref = lookup_user_key(NULL, keyid, 0, 1, KEY_VIEW);	if (IS_ERR(key_ref)) {		/* viewing a key under construction is permitted if we have the		 * authorisation token handy */		if (PTR_ERR(key_ref) == -EACCES) {			instkey = key_get_instantiation_authkey(keyid);			if (!IS_ERR(instkey)) {				key_put(instkey);				key_ref = lookup_user_key(NULL, keyid,							  0, 1, 0);				if (!IS_ERR(key_ref))					goto okay;			}		}		ret = PTR_ERR(key_ref);		goto error;	}okay:	/* calculate how much description we're going to return */	ret = -ENOMEM;	tmpbuf = kmalloc(PAGE_SIZE, GFP_KERNEL);	if (!tmpbuf)		goto error2;	key = key_ref_to_ptr(key_ref);	ret = snprintf(tmpbuf, PAGE_SIZE - 1,		       "%s;%d;%d;%08x;%s",		       key_ref_to_ptr(key_ref)->type->name,		       key_ref_to_ptr(key_ref)->uid,		       key_ref_to_ptr(key_ref)->gid,		       key_ref_to_ptr(key_ref)->perm,		       key_ref_to_ptr(key_ref)->description ?		       key_ref_to_ptr(key_ref)->description : ""		       );	/* include a NUL char at the end of the data */	if (ret > PAGE_SIZE - 1)		ret = PAGE_SIZE - 1;	tmpbuf[ret] = 0;	ret++;	/* consider returning the data */	if (buffer && buflen > 0) {		if (buflen > ret)			buflen = ret;		if (copy_to_user(buffer, tmpbuf, buflen) != 0)			ret = -EFAULT;	}	kfree(tmpbuf); error2:	key_ref_put(key_ref); error:	return ret;} /* end keyctl_describe_key() *//*****************************************************************************//* * search the specified keyring for a matching key * - the start keyring must be searchable * - nested keyrings may also be searched if they are searchable * - only keys with search permission may be found * - if a key is found, it will be attached to the destination keyring if *   there's one specified * - implements keyctl(KEYCTL_SEARCH) */long keyctl_keyring_search(key_serial_t ringid,			   const char __user *_type,			   const char __user *_description,			   key_serial_t destringid){	struct key_type *ktype;	key_ref_t keyring_ref, key_ref, dest_ref;	char type[32], *description;	long ret;	/* pull the type and description into kernel space */	ret = key_get_type_from_user(type, _type, sizeof(type));	if (ret < 0)		goto error;	description = strndup_user(_description, PAGE_SIZE);	if (IS_ERR(description)) {		ret = PTR_ERR(description);		goto error;	}	/* get the keyring at which to begin the search */	keyring_ref = lookup_user_key(NULL, ringid, 0, 0, KEY_SEARCH);	if (IS_ERR(keyring_ref)) {		ret = PTR_ERR(keyring_ref);		goto error2;	}	/* get the destination keyring if specified */	dest_ref = NULL;	if (destringid) {		dest_ref = lookup_user_key(NULL, destringid, 1, 0, KEY_WRITE);		if (IS_ERR(dest_ref)) {			ret = PTR_ERR(dest_ref);			goto error3;		}	}	/* find the key type */	ktype = key_type_lookup(type);	if (IS_ERR(ktype)) {		ret = PTR_ERR(ktype);		goto error4;	}	/* do the search */	key_ref = keyring_search(keyring_ref, ktype, description);	if (IS_ERR(key_ref)) {		ret = PTR_ERR(key_ref);		/* treat lack or presence of a negative key the same */		if (ret == -EAGAIN)

⌨️ 快捷键说明

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