• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1  /* user_defined.c: user defined key type
2   *
3   * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
4   * Written by David Howells (dhowells@redhat.com)
5   *
6   * This program is free software; you can redistribute it and/or
7   * modify it under the terms of the GNU General Public License
8   * as published by the Free Software Foundation; either version
9   * 2 of the License, or (at your option) any later version.
10   */
11  
12  #include <linux/module.h>
13  #include <linux/init.h>
14  #include <linux/slab.h>
15  #include <linux/seq_file.h>
16  #include <linux/err.h>
17  #include <keys/user-type.h>
18  #include <asm/uaccess.h>
19  #include "internal.h"
20  
21  static int logon_vet_description(const char *desc);
22  
23  /*
24   * user defined keys take an arbitrary string as the description and an
25   * arbitrary blob of data as the payload
26   */
27  struct key_type key_type_user = {
28  	.name		= "user",
29  	.instantiate	= user_instantiate,
30  	.update		= user_update,
31  	.match		= user_match,
32  	.revoke		= user_revoke,
33  	.destroy	= user_destroy,
34  	.describe	= user_describe,
35  	.read		= user_read,
36  };
37  
38  EXPORT_SYMBOL_GPL(key_type_user);
39  
40  /*
41   * This key type is essentially the same as key_type_user, but it does
42   * not define a .read op. This is suitable for storing username and
43   * password pairs in the keyring that you do not want to be readable
44   * from userspace.
45   */
46  struct key_type key_type_logon = {
47  	.name			= "logon",
48  	.instantiate		= user_instantiate,
49  	.update			= user_update,
50  	.match			= user_match,
51  	.revoke			= user_revoke,
52  	.destroy		= user_destroy,
53  	.describe		= user_describe,
54  	.vet_description	= logon_vet_description,
55  };
56  EXPORT_SYMBOL_GPL(key_type_logon);
57  
58  /*
59   * instantiate a user defined key
60   */
user_instantiate(struct key * key,const void * data,size_t datalen)61  int user_instantiate(struct key *key, const void *data, size_t datalen)
62  {
63  	struct user_key_payload *upayload;
64  	int ret;
65  
66  	ret = -EINVAL;
67  	if (datalen <= 0 || datalen > 32767 || !data)
68  		goto error;
69  
70  	ret = key_payload_reserve(key, datalen);
71  	if (ret < 0)
72  		goto error;
73  
74  	ret = -ENOMEM;
75  	upayload = kmalloc(sizeof(*upayload) + datalen, GFP_KERNEL);
76  	if (!upayload)
77  		goto error;
78  
79  	/* attach the data */
80  	upayload->datalen = datalen;
81  	memcpy(upayload->data, data, datalen);
82  	rcu_assign_keypointer(key, upayload);
83  	ret = 0;
84  
85  error:
86  	return ret;
87  }
88  
89  EXPORT_SYMBOL_GPL(user_instantiate);
90  
91  /*
92   * update a user defined key
93   * - the key's semaphore is write-locked
94   */
user_update(struct key * key,const void * data,size_t datalen)95  int user_update(struct key *key, const void *data, size_t datalen)
96  {
97  	struct user_key_payload *upayload, *zap;
98  	int ret;
99  
100  	ret = -EINVAL;
101  	if (datalen <= 0 || datalen > 32767 || !data)
102  		goto error;
103  
104  	/* construct a replacement payload */
105  	ret = -ENOMEM;
106  	upayload = kmalloc(sizeof(*upayload) + datalen, GFP_KERNEL);
107  	if (!upayload)
108  		goto error;
109  
110  	upayload->datalen = datalen;
111  	memcpy(upayload->data, data, datalen);
112  
113  	/* check the quota and attach the new data */
114  	zap = upayload;
115  
116  	ret = key_payload_reserve(key, datalen);
117  
118  	if (ret == 0) {
119  		/* attach the new data, displacing the old */
120  		zap = key->payload.data;
121  		rcu_assign_keypointer(key, upayload);
122  		key->expiry = 0;
123  	}
124  
125  	if (zap)
126  		kfree_rcu(zap, rcu);
127  
128  error:
129  	return ret;
130  }
131  
132  EXPORT_SYMBOL_GPL(user_update);
133  
134  /*
135   * match users on their name
136   */
user_match(const struct key * key,const void * description)137  int user_match(const struct key *key, const void *description)
138  {
139  	return strcmp(key->description, description) == 0;
140  }
141  
142  EXPORT_SYMBOL_GPL(user_match);
143  
144  /*
145   * dispose of the links from a revoked keyring
146   * - called with the key sem write-locked
147   */
user_revoke(struct key * key)148  void user_revoke(struct key *key)
149  {
150  	struct user_key_payload *upayload = key->payload.data;
151  
152  	/* clear the quota */
153  	key_payload_reserve(key, 0);
154  
155  	if (upayload) {
156  		rcu_assign_keypointer(key, NULL);
157  		kfree_rcu(upayload, rcu);
158  	}
159  }
160  
161  EXPORT_SYMBOL(user_revoke);
162  
163  /*
164   * dispose of the data dangling from the corpse of a user key
165   */
user_destroy(struct key * key)166  void user_destroy(struct key *key)
167  {
168  	struct user_key_payload *upayload = key->payload.data;
169  
170  	kfree(upayload);
171  }
172  
173  EXPORT_SYMBOL_GPL(user_destroy);
174  
175  /*
176   * describe the user key
177   */
user_describe(const struct key * key,struct seq_file * m)178  void user_describe(const struct key *key, struct seq_file *m)
179  {
180  	seq_puts(m, key->description);
181  	if (key_is_instantiated(key))
182  		seq_printf(m, ": %u", key->datalen);
183  }
184  
185  EXPORT_SYMBOL_GPL(user_describe);
186  
187  /*
188   * read the key data
189   * - the key's semaphore is read-locked
190   */
user_read(const struct key * key,char __user * buffer,size_t buflen)191  long user_read(const struct key *key, char __user *buffer, size_t buflen)
192  {
193  	struct user_key_payload *upayload;
194  	long ret;
195  
196  	upayload = rcu_dereference_key(key);
197  	ret = upayload->datalen;
198  
199  	/* we can return the data as is */
200  	if (buffer && buflen > 0) {
201  		if (buflen > upayload->datalen)
202  			buflen = upayload->datalen;
203  
204  		if (copy_to_user(buffer, upayload->data, buflen) != 0)
205  			ret = -EFAULT;
206  	}
207  
208  	return ret;
209  }
210  
211  EXPORT_SYMBOL_GPL(user_read);
212  
213  /* Vet the description for a "logon" key */
logon_vet_description(const char * desc)214  static int logon_vet_description(const char *desc)
215  {
216  	char *p;
217  
218  	/* require a "qualified" description string */
219  	p = strchr(desc, ':');
220  	if (!p)
221  		return -EINVAL;
222  
223  	/* also reject description with ':' as first char */
224  	if (p == desc)
225  		return -EINVAL;
226  
227  	return 0;
228  }
229