Branch data Line data Source code
1 : : /*
2 : : * linux/net/sunrpc/auth_unix.c
3 : : *
4 : : * UNIX-style authentication; no AUTH_SHORT support
5 : : *
6 : : * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
7 : : */
8 : :
9 : : #include <linux/slab.h>
10 : : #include <linux/types.h>
11 : : #include <linux/sched.h>
12 : : #include <linux/module.h>
13 : : #include <linux/sunrpc/clnt.h>
14 : : #include <linux/sunrpc/auth.h>
15 : : #include <linux/user_namespace.h>
16 : :
17 : : #define NFS_NGROUPS 16
18 : :
19 : : struct unx_cred {
20 : : struct rpc_cred uc_base;
21 : : kgid_t uc_gid;
22 : : kgid_t uc_gids[NFS_NGROUPS];
23 : : };
24 : : #define uc_uid uc_base.cr_uid
25 : :
26 : : #define UNX_WRITESLACK (21 + (UNX_MAXNODENAME >> 2))
27 : :
28 : : #ifdef RPC_DEBUG
29 : : # define RPCDBG_FACILITY RPCDBG_AUTH
30 : : #endif
31 : :
32 : : static struct rpc_auth unix_auth;
33 : : static const struct rpc_credops unix_credops;
34 : :
35 : : static struct rpc_auth *
36 : 0 : unx_create(struct rpc_auth_create_args *args, struct rpc_clnt *clnt)
37 : : {
38 : : dprintk("RPC: creating UNIX authenticator for client %p\n",
39 : : clnt);
40 : : atomic_inc(&unix_auth.au_count);
41 : 0 : return &unix_auth;
42 : : }
43 : :
44 : : static void
45 : 0 : unx_destroy(struct rpc_auth *auth)
46 : : {
47 : : dprintk("RPC: destroying UNIX authenticator %p\n", auth);
48 : 0 : rpcauth_clear_credcache(auth->au_credcache);
49 : 0 : }
50 : :
51 : : /*
52 : : * Lookup AUTH_UNIX creds for current process
53 : : */
54 : : static struct rpc_cred *
55 : 0 : unx_lookup_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags)
56 : : {
57 : 0 : return rpcauth_lookup_credcache(auth, acred, flags);
58 : : }
59 : :
60 : : static struct rpc_cred *
61 : 0 : unx_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags)
62 : : {
63 : : struct unx_cred *cred;
64 : : unsigned int groups = 0;
65 : : unsigned int i;
66 : :
67 : : dprintk("RPC: allocating UNIX cred for uid %d gid %d\n",
68 : : from_kuid(&init_user_ns, acred->uid),
69 : : from_kgid(&init_user_ns, acred->gid));
70 : :
71 [ # # ]: 0 : if (!(cred = kmalloc(sizeof(*cred), GFP_NOFS)))
72 : : return ERR_PTR(-ENOMEM);
73 : :
74 : 0 : rpcauth_init_cred(&cred->uc_base, acred, auth, &unix_credops);
75 : 0 : cred->uc_base.cr_flags = 1UL << RPCAUTH_CRED_UPTODATE;
76 : :
77 [ # # ]: 0 : if (acred->group_info != NULL)
78 : 0 : groups = acred->group_info->ngroups;
79 [ # # ]: 0 : if (groups > NFS_NGROUPS)
80 : : groups = NFS_NGROUPS;
81 : :
82 : 0 : cred->uc_gid = acred->gid;
83 [ # # ]: 0 : for (i = 0; i < groups; i++)
84 : 0 : cred->uc_gids[i] = GROUP_AT(acred->group_info, i);
85 [ # # ]: 0 : if (i < NFS_NGROUPS)
86 : 0 : cred->uc_gids[i] = INVALID_GID;
87 : :
88 : 0 : return &cred->uc_base;
89 : : }
90 : :
91 : : static void
92 : : unx_free_cred(struct unx_cred *unx_cred)
93 : : {
94 : : dprintk("RPC: unx_free_cred %p\n", unx_cred);
95 : 0 : kfree(unx_cred);
96 : : }
97 : :
98 : : static void
99 : 0 : unx_free_cred_callback(struct rcu_head *head)
100 : : {
101 : 0 : struct unx_cred *unx_cred = container_of(head, struct unx_cred, uc_base.cr_rcu);
102 : : unx_free_cred(unx_cred);
103 : 0 : }
104 : :
105 : : static void
106 : 0 : unx_destroy_cred(struct rpc_cred *cred)
107 : : {
108 : 0 : call_rcu(&cred->cr_rcu, unx_free_cred_callback);
109 : 0 : }
110 : :
111 : : /*
112 : : * Match credentials against current process creds.
113 : : * The root_override argument takes care of cases where the caller may
114 : : * request root creds (e.g. for NFS swapping).
115 : : */
116 : : static int
117 : 0 : unx_match(struct auth_cred *acred, struct rpc_cred *rcred, int flags)
118 : : {
119 : : struct unx_cred *cred = container_of(rcred, struct unx_cred, uc_base);
120 : : unsigned int groups = 0;
121 : : unsigned int i;
122 : :
123 : :
124 [ # # ][ # # ]: 0 : if (!uid_eq(cred->uc_uid, acred->uid) || !gid_eq(cred->uc_gid, acred->gid))
125 : : return 0;
126 : :
127 [ # # ]: 0 : if (acred->group_info != NULL)
128 : 0 : groups = acred->group_info->ngroups;
129 [ # # ]: 0 : if (groups > NFS_NGROUPS)
130 : : groups = NFS_NGROUPS;
131 [ # # ]: 0 : for (i = 0; i < groups ; i++)
132 [ # # ]: 0 : if (!gid_eq(cred->uc_gids[i], GROUP_AT(acred->group_info, i)))
133 : : return 0;
134 [ # # ][ # # ]: 0 : if (groups < NFS_NGROUPS && gid_valid(cred->uc_gids[groups]))
135 : : return 0;
136 : : return 1;
137 : : }
138 : :
139 : : /*
140 : : * Marshal credentials.
141 : : * Maybe we should keep a cached credential for performance reasons.
142 : : */
143 : : static __be32 *
144 : 0 : unx_marshal(struct rpc_task *task, __be32 *p)
145 : : {
146 : 0 : struct rpc_clnt *clnt = task->tk_client;
147 : 0 : struct unx_cred *cred = container_of(task->tk_rqstp->rq_cred, struct unx_cred, uc_base);
148 : : __be32 *base, *hold;
149 : : int i;
150 : :
151 : 0 : *p++ = htonl(RPC_AUTH_UNIX);
152 : 0 : base = p++;
153 : 0 : *p++ = htonl(jiffies/HZ);
154 : :
155 : : /*
156 : : * Copy the UTS nodename captured when the client was created.
157 : : */
158 : 0 : p = xdr_encode_array(p, clnt->cl_nodename, clnt->cl_nodelen);
159 : :
160 : 0 : *p++ = htonl((u32) from_kuid(&init_user_ns, cred->uc_uid));
161 : 0 : *p++ = htonl((u32) from_kgid(&init_user_ns, cred->uc_gid));
162 : 0 : hold = p++;
163 [ # # ][ # # ]: 0 : for (i = 0; i < 16 && gid_valid(cred->uc_gids[i]); i++)
164 : 0 : *p++ = htonl((u32) from_kgid(&init_user_ns, cred->uc_gids[i]));
165 [ # # ]: 0 : *hold = htonl(p - hold - 1); /* gid array length */
166 [ # # ]: 0 : *base = htonl((p - base - 1) << 2); /* cred length */
167 : :
168 : 0 : *p++ = htonl(RPC_AUTH_NULL);
169 : 0 : *p++ = htonl(0);
170 : :
171 : 0 : return p;
172 : : }
173 : :
174 : : /*
175 : : * Refresh credentials. This is a no-op for AUTH_UNIX
176 : : */
177 : : static int
178 : 0 : unx_refresh(struct rpc_task *task)
179 : : {
180 : 0 : set_bit(RPCAUTH_CRED_UPTODATE, &task->tk_rqstp->rq_cred->cr_flags);
181 : 0 : return 0;
182 : : }
183 : :
184 : : static __be32 *
185 : 0 : unx_validate(struct rpc_task *task, __be32 *p)
186 : : {
187 : : rpc_authflavor_t flavor;
188 : : u32 size;
189 : :
190 : 0 : flavor = ntohl(*p++);
191 [ # # ]: 0 : if (flavor != RPC_AUTH_NULL &&
192 : : flavor != RPC_AUTH_UNIX &&
193 : : flavor != RPC_AUTH_SHORT) {
194 : 0 : printk("RPC: bad verf flavor: %u\n", flavor);
195 : 0 : return ERR_PTR(-EIO);
196 : : }
197 : :
198 : 0 : size = ntohl(*p++);
199 [ # # ]: 0 : if (size > RPC_MAX_AUTH_SIZE) {
200 : 0 : printk("RPC: giant verf size: %u\n", size);
201 : 0 : return ERR_PTR(-EIO);
202 : : }
203 : 0 : task->tk_rqstp->rq_cred->cr_auth->au_rslack = (size >> 2) + 2;
204 : 0 : p += (size >> 2);
205 : :
206 : 0 : return p;
207 : : }
208 : :
209 : 0 : int __init rpc_init_authunix(void)
210 : : {
211 : 0 : return rpcauth_init_credcache(&unix_auth);
212 : : }
213 : :
214 : 0 : void rpc_destroy_authunix(void)
215 : : {
216 : 0 : rpcauth_destroy_credcache(&unix_auth);
217 : 0 : }
218 : :
219 : : const struct rpc_authops authunix_ops = {
220 : : .owner = THIS_MODULE,
221 : : .au_flavor = RPC_AUTH_UNIX,
222 : : .au_name = "UNIX",
223 : : .create = unx_create,
224 : : .destroy = unx_destroy,
225 : : .lookup_cred = unx_lookup_cred,
226 : : .crcreate = unx_create_cred,
227 : : };
228 : :
229 : : static
230 : : struct rpc_auth unix_auth = {
231 : : .au_cslack = UNX_WRITESLACK,
232 : : .au_rslack = 2, /* assume AUTH_NULL verf */
233 : : .au_ops = &authunix_ops,
234 : : .au_flavor = RPC_AUTH_UNIX,
235 : : .au_count = ATOMIC_INIT(0),
236 : : };
237 : :
238 : : static
239 : : const struct rpc_credops unix_credops = {
240 : : .cr_name = "AUTH_UNIX",
241 : : .crdestroy = unx_destroy_cred,
242 : : .crbind = rpcauth_generic_bind_cred,
243 : : .crmatch = unx_match,
244 : : .crmarshal = unx_marshal,
245 : : .crrefresh = unx_refresh,
246 : : .crvalidate = unx_validate,
247 : : };
|