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