request_key.c 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359
  1. /* request_key.c: request a key from userspace
  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. #include <linux/module.h>
  12. #include <linux/sched.h>
  13. #include <linux/kmod.h>
  14. #include <linux/err.h>
  15. #include "internal.h"
  16. struct key_construction {
  17. struct list_head link; /* link in construction queue */
  18. struct key *key; /* key being constructed */
  19. };
  20. /* when waiting for someone else's keys, you get added to this */
  21. DECLARE_WAIT_QUEUE_HEAD(request_key_conswq);
  22. /*****************************************************************************/
  23. /*
  24. * request userspace finish the construction of a key
  25. * - execute "/sbin/request-key <op> <key> <uid> <gid> <keyring> <keyring> <keyring> <info>"
  26. * - if callout_info is an empty string, it'll be rendered as a "-" instead
  27. */
  28. static int call_request_key(struct key *key,
  29. const char *op,
  30. const char *callout_info)
  31. {
  32. struct task_struct *tsk = current;
  33. unsigned long flags;
  34. key_serial_t prkey, sskey;
  35. char *argv[10], *envp[3], uid_str[12], gid_str[12];
  36. char key_str[12], keyring_str[3][12];
  37. int i;
  38. /* record the UID and GID */
  39. sprintf(uid_str, "%d", current->fsuid);
  40. sprintf(gid_str, "%d", current->fsgid);
  41. /* we say which key is under construction */
  42. sprintf(key_str, "%d", key->serial);
  43. /* we specify the process's default keyrings */
  44. sprintf(keyring_str[0], "%d",
  45. tsk->thread_keyring ? tsk->thread_keyring->serial : 0);
  46. prkey = 0;
  47. if (tsk->signal->process_keyring)
  48. prkey = tsk->signal->process_keyring->serial;
  49. sskey = 0;
  50. spin_lock_irqsave(&tsk->sighand->siglock, flags);
  51. if (tsk->signal->session_keyring)
  52. sskey = tsk->signal->session_keyring->serial;
  53. spin_unlock_irqrestore(&tsk->sighand->siglock, flags);
  54. if (!sskey)
  55. sskey = tsk->user->session_keyring->serial;
  56. sprintf(keyring_str[1], "%d", prkey);
  57. sprintf(keyring_str[2], "%d", sskey);
  58. /* set up a minimal environment */
  59. i = 0;
  60. envp[i++] = "HOME=/";
  61. envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
  62. envp[i] = NULL;
  63. /* set up the argument list */
  64. i = 0;
  65. argv[i++] = "/sbin/request-key";
  66. argv[i++] = (char *) op;
  67. argv[i++] = key_str;
  68. argv[i++] = uid_str;
  69. argv[i++] = gid_str;
  70. argv[i++] = keyring_str[0];
  71. argv[i++] = keyring_str[1];
  72. argv[i++] = keyring_str[2];
  73. argv[i++] = callout_info[0] ? (char *) callout_info : "-";
  74. argv[i] = NULL;
  75. /* do it */
  76. return call_usermodehelper(argv[0], argv, envp, 1);
  77. } /* end call_request_key() */
  78. /*****************************************************************************/
  79. /*
  80. * call out to userspace for the key
  81. * - called with the construction sem held, but the sem is dropped here
  82. * - we ignore program failure and go on key status instead
  83. */
  84. static struct key *__request_key_construction(struct key_type *type,
  85. const char *description,
  86. const char *callout_info)
  87. {
  88. struct key_construction cons;
  89. struct timespec now;
  90. struct key *key;
  91. int ret, negative;
  92. /* create a key and add it to the queue */
  93. key = key_alloc(type, description,
  94. current->fsuid, current->fsgid, KEY_USR_ALL, 0);
  95. if (IS_ERR(key))
  96. goto alloc_failed;
  97. write_lock(&key->lock);
  98. key->flags |= KEY_FLAG_USER_CONSTRUCT;
  99. write_unlock(&key->lock);
  100. cons.key = key;
  101. list_add_tail(&cons.link, &key->user->consq);
  102. /* we drop the construction sem here on behalf of the caller */
  103. up_write(&key_construction_sem);
  104. /* make the call */
  105. ret = call_request_key(key, "create", callout_info);
  106. if (ret < 0)
  107. goto request_failed;
  108. /* if the key wasn't instantiated, then we want to give an error */
  109. ret = -ENOKEY;
  110. if (!(key->flags & KEY_FLAG_INSTANTIATED))
  111. goto request_failed;
  112. down_write(&key_construction_sem);
  113. list_del(&cons.link);
  114. up_write(&key_construction_sem);
  115. /* also give an error if the key was negatively instantiated */
  116. check_not_negative:
  117. if (key->flags & KEY_FLAG_NEGATIVE) {
  118. key_put(key);
  119. key = ERR_PTR(-ENOKEY);
  120. }
  121. out:
  122. return key;
  123. request_failed:
  124. /* it wasn't instantiated
  125. * - remove from construction queue
  126. * - mark the key as dead
  127. */
  128. negative = 0;
  129. down_write(&key_construction_sem);
  130. list_del(&cons.link);
  131. write_lock(&key->lock);
  132. key->flags &= ~KEY_FLAG_USER_CONSTRUCT;
  133. /* check it didn't get instantiated between the check and the down */
  134. if (!(key->flags & KEY_FLAG_INSTANTIATED)) {
  135. key->flags |= KEY_FLAG_INSTANTIATED | KEY_FLAG_NEGATIVE;
  136. negative = 1;
  137. }
  138. write_unlock(&key->lock);
  139. up_write(&key_construction_sem);
  140. if (!negative)
  141. goto check_not_negative; /* surprisingly, the key got
  142. * instantiated */
  143. /* set the timeout and store in the session keyring if we can */
  144. now = current_kernel_time();
  145. key->expiry = now.tv_sec + key_negative_timeout;
  146. if (current->signal->session_keyring) {
  147. unsigned long flags;
  148. struct key *keyring;
  149. spin_lock_irqsave(&current->sighand->siglock, flags);
  150. keyring = current->signal->session_keyring;
  151. atomic_inc(&keyring->usage);
  152. spin_unlock_irqrestore(&current->sighand->siglock, flags);
  153. key_link(keyring, key);
  154. key_put(keyring);
  155. }
  156. key_put(key);
  157. /* notify anyone who was waiting */
  158. wake_up_all(&request_key_conswq);
  159. key = ERR_PTR(ret);
  160. goto out;
  161. alloc_failed:
  162. up_write(&key_construction_sem);
  163. goto out;
  164. } /* end __request_key_construction() */
  165. /*****************************************************************************/
  166. /*
  167. * call out to userspace to request the key
  168. * - we check the construction queue first to see if an appropriate key is
  169. * already being constructed by userspace
  170. */
  171. static struct key *request_key_construction(struct key_type *type,
  172. const char *description,
  173. struct key_user *user,
  174. const char *callout_info)
  175. {
  176. struct key_construction *pcons;
  177. struct key *key, *ckey;
  178. DECLARE_WAITQUEUE(myself, current);
  179. /* see if there's such a key under construction already */
  180. down_write(&key_construction_sem);
  181. list_for_each_entry(pcons, &user->consq, link) {
  182. ckey = pcons->key;
  183. if (ckey->type != type)
  184. continue;
  185. if (type->match(ckey, description))
  186. goto found_key_under_construction;
  187. }
  188. /* see about getting userspace to construct the key */
  189. key = __request_key_construction(type, description, callout_info);
  190. error:
  191. return key;
  192. /* someone else has the same key under construction
  193. * - we want to keep an eye on their key
  194. */
  195. found_key_under_construction:
  196. atomic_inc(&ckey->usage);
  197. up_write(&key_construction_sem);
  198. /* wait for the key to be completed one way or another */
  199. add_wait_queue(&request_key_conswq, &myself);
  200. for (;;) {
  201. set_current_state(TASK_UNINTERRUPTIBLE);
  202. if (!(ckey->flags & KEY_FLAG_USER_CONSTRUCT))
  203. break;
  204. schedule();
  205. }
  206. set_current_state(TASK_RUNNING);
  207. remove_wait_queue(&request_key_conswq, &myself);
  208. /* we'll need to search this process's keyrings to see if the key is
  209. * now there since we can't automatically assume it's also available
  210. * there */
  211. key_put(ckey);
  212. ckey = NULL;
  213. key = NULL; /* request a retry */
  214. goto error;
  215. } /* end request_key_construction() */
  216. /*****************************************************************************/
  217. /*
  218. * request a key
  219. * - search the process's keyrings
  220. * - check the list of keys being created or updated
  221. * - call out to userspace for a key if requested (supplementary info can be
  222. * passed)
  223. */
  224. struct key *request_key(struct key_type *type,
  225. const char *description,
  226. const char *callout_info)
  227. {
  228. struct key_user *user;
  229. struct key *key;
  230. /* search all the process keyrings for a key */
  231. key = search_process_keyrings_aux(type, description, type->match);
  232. if (PTR_ERR(key) == -EAGAIN) {
  233. /* the search failed, but the keyrings were searchable, so we
  234. * should consult userspace if we can */
  235. key = ERR_PTR(-ENOKEY);
  236. if (!callout_info)
  237. goto error;
  238. /* - get hold of the user's construction queue */
  239. user = key_user_lookup(current->fsuid);
  240. if (!user) {
  241. key = ERR_PTR(-ENOMEM);
  242. goto error;
  243. }
  244. for (;;) {
  245. /* ask userspace (returns NULL if it waited on a key
  246. * being constructed) */
  247. key = request_key_construction(type, description,
  248. user, callout_info);
  249. if (key)
  250. break;
  251. /* someone else made the key we want, so we need to
  252. * search again as it might now be available to us */
  253. key = search_process_keyrings_aux(type, description,
  254. type->match);
  255. if (PTR_ERR(key) != -EAGAIN)
  256. break;
  257. }
  258. key_user_put(user);
  259. }
  260. error:
  261. return key;
  262. } /* end request_key() */
  263. EXPORT_SYMBOL(request_key);
  264. /*****************************************************************************/
  265. /*
  266. * validate a key
  267. */
  268. int key_validate(struct key *key)
  269. {
  270. struct timespec now;
  271. int ret = 0;
  272. if (key) {
  273. /* check it's still accessible */
  274. ret = -EKEYREVOKED;
  275. if (key->flags & (KEY_FLAG_REVOKED | KEY_FLAG_DEAD))
  276. goto error;
  277. /* check it hasn't expired */
  278. ret = 0;
  279. if (key->expiry) {
  280. now = current_kernel_time();
  281. if (now.tv_sec >= key->expiry)
  282. ret = -EKEYEXPIRED;
  283. }
  284. }
  285. error:
  286. return ret;
  287. } /* end key_validate() */
  288. EXPORT_SYMBOL(key_validate);