Merge branch 'master'
[sfrench/cifs-2.6.git] / security / keys / request_key_auth.c
1 /* request_key_auth.c: request key authorisation controlling key def
2  *
3  * Copyright (C) 2005 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/err.h>
15 #include <linux/seq_file.h>
16 #include "internal.h"
17
18 static int request_key_auth_instantiate(struct key *, const void *, size_t);
19 static void request_key_auth_describe(const struct key *, struct seq_file *);
20 static void request_key_auth_destroy(struct key *);
21
22 /*
23  * the request-key authorisation key type definition
24  */
25 struct key_type key_type_request_key_auth = {
26         .name           = ".request_key_auth",
27         .def_datalen    = sizeof(struct request_key_auth),
28         .instantiate    = request_key_auth_instantiate,
29         .describe       = request_key_auth_describe,
30         .destroy        = request_key_auth_destroy,
31 };
32
33 /*****************************************************************************/
34 /*
35  * instantiate a request-key authorisation record
36  */
37 static int request_key_auth_instantiate(struct key *key,
38                                         const void *data,
39                                         size_t datalen)
40 {
41         struct request_key_auth *rka, *irka;
42         struct key *instkey;
43         int ret;
44
45         ret = -ENOMEM;
46         rka = kmalloc(sizeof(*rka), GFP_KERNEL);
47         if (rka) {
48                 /* see if the calling process is already servicing the key
49                  * request of another process */
50                 instkey = key_get_instantiation_authkey(0);
51                 if (!IS_ERR(instkey)) {
52                         /* it is - use that instantiation context here too */
53                         irka = instkey->payload.data;
54                         rka->context = irka->context;
55                         rka->pid = irka->pid;
56                         key_put(instkey);
57                 }
58                 else {
59                         /* it isn't - use this process as the context */
60                         rka->context = current;
61                         rka->pid = current->pid;
62                 }
63
64                 rka->target_key = key_get((struct key *) data);
65                 key->payload.data = rka;
66                 ret = 0;
67         }
68
69         return ret;
70
71 } /* end request_key_auth_instantiate() */
72
73 /*****************************************************************************/
74 /*
75  *
76  */
77 static void request_key_auth_describe(const struct key *key,
78                                       struct seq_file *m)
79 {
80         struct request_key_auth *rka = key->payload.data;
81
82         seq_puts(m, "key:");
83         seq_puts(m, key->description);
84         seq_printf(m, " pid:%d", rka->pid);
85
86 } /* end request_key_auth_describe() */
87
88 /*****************************************************************************/
89 /*
90  * destroy an instantiation authorisation token key
91  */
92 static void request_key_auth_destroy(struct key *key)
93 {
94         struct request_key_auth *rka = key->payload.data;
95
96         kenter("{%d}", key->serial);
97
98         key_put(rka->target_key);
99
100 } /* end request_key_auth_destroy() */
101
102 /*****************************************************************************/
103 /*
104  * create a session keyring to be for the invokation of /sbin/request-key and
105  * stick an authorisation token in it
106  */
107 struct key *request_key_auth_new(struct key *target, struct key **_rkakey)
108 {
109         struct key *keyring, *rkakey = NULL;
110         char desc[20];
111         int ret;
112
113         kenter("%d,", target->serial);
114
115         /* allocate a new session keyring */
116         sprintf(desc, "_req.%u", target->serial);
117
118         keyring = keyring_alloc(desc, current->fsuid, current->fsgid, 1, NULL);
119         if (IS_ERR(keyring)) {
120                 kleave("= %ld", PTR_ERR(keyring));
121                 return keyring;
122         }
123
124         /* allocate the auth key */
125         sprintf(desc, "%x", target->serial);
126
127         rkakey = key_alloc(&key_type_request_key_auth, desc,
128                            current->fsuid, current->fsgid,
129                            KEY_POS_VIEW | KEY_USR_VIEW, 1);
130         if (IS_ERR(rkakey)) {
131                 key_put(keyring);
132                 kleave("= %ld", PTR_ERR(rkakey));
133                 return rkakey;
134         }
135
136         /* construct and attach to the keyring */
137         ret = key_instantiate_and_link(rkakey, target, 0, keyring, NULL);
138         if (ret < 0) {
139                 key_revoke(rkakey);
140                 key_put(rkakey);
141                 key_put(keyring);
142                 kleave("= %d", ret);
143                 return ERR_PTR(ret);
144         }
145
146         *_rkakey = rkakey;
147         kleave(" = {%d} ({%d})", keyring->serial, rkakey->serial);
148         return keyring;
149
150 } /* end request_key_auth_new() */
151
152 /*****************************************************************************/
153 /*
154  * get the authorisation key for instantiation of a specific key if attached to
155  * the current process's keyrings
156  * - this key is inserted into a keyring and that is set as /sbin/request-key's
157  *   session keyring
158  * - a target_id of zero specifies any valid token
159  */
160 struct key *key_get_instantiation_authkey(key_serial_t target_id)
161 {
162         struct task_struct *tsk = current;
163         struct key *instkey;
164
165         /* we must have our own personal session keyring */
166         if (!tsk->signal->session_keyring)
167                 return ERR_PTR(-EACCES);
168
169         /* and it must contain a suitable request authorisation key
170          * - lock RCU against session keyring changing
171          */
172         rcu_read_lock();
173
174         instkey = keyring_search_instkey(
175                 rcu_dereference(tsk->signal->session_keyring), target_id);
176
177         rcu_read_unlock();
178         return instkey;
179
180 } /* end key_get_instantiation_authkey() */