VServer 1.9.2 (patch-2.6.8.1-vs1.9.2.diff)
[linux-2.6.git] / net / sunrpc / auth_unix.c
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/types.h>
10 #include <linux/sched.h>
11 #include <linux/module.h>
12 #include <linux/socket.h>
13 #include <linux/in.h>
14 #include <linux/sunrpc/clnt.h>
15 #include <linux/sunrpc/auth.h>
16 #include <linux/vserver/xid.h>
17
18 #define NFS_NGROUPS     16
19
20 struct unx_cred {
21         struct rpc_cred         uc_base;
22         gid_t                   uc_gid;
23         xid_t                   uc_xid;
24         uid_t                   uc_puid;                /* process uid */
25         gid_t                   uc_pgid;                /* process gid */
26         xid_t                   uc_pxid;                /* process xid */
27         gid_t                   uc_gids[NFS_NGROUPS];
28 };
29 #define uc_uid                  uc_base.cr_uid
30 #define uc_count                uc_base.cr_count
31 #define uc_flags                uc_base.cr_flags
32 #define uc_expire               uc_base.cr_expire
33
34 #define UNX_CRED_EXPIRE         (60 * HZ)
35
36 #define UNX_WRITESLACK          (21 + (UNX_MAXNODENAME >> 2))
37
38 #ifdef RPC_DEBUG
39 # define RPCDBG_FACILITY        RPCDBG_AUTH
40 #endif
41
42 static struct rpc_credops       unix_credops;
43
44 static struct rpc_auth *
45 unx_create(struct rpc_clnt *clnt, rpc_authflavor_t flavor)
46 {
47         struct rpc_auth *auth;
48
49         dprintk("RPC: creating UNIX authenticator for client %p\n", clnt);
50         if (!(auth = (struct rpc_auth *) kmalloc(sizeof(*auth), GFP_KERNEL)))
51                 return NULL;
52         auth->au_cslack = UNX_WRITESLACK;
53         auth->au_rslack = 2;    /* assume AUTH_NULL verf */
54         auth->au_expire = UNX_CRED_EXPIRE;
55         auth->au_ops = &authunix_ops;
56
57         rpcauth_init_credcache(auth);
58
59         return auth;
60 }
61
62 static void
63 unx_destroy(struct rpc_auth *auth)
64 {
65         dprintk("RPC: destroying UNIX authenticator %p\n", auth);
66         rpcauth_free_credcache(auth);
67 }
68
69 static struct rpc_cred *
70 unx_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags)
71 {
72         struct unx_cred *cred;
73         int             i;
74
75         dprintk("RPC:      allocating UNIX cred for uid %d gid %d\n",
76                                 acred->uid, acred->gid);
77
78         if (!(cred = (struct unx_cred *) kmalloc(sizeof(*cred), GFP_KERNEL)))
79                 return NULL;
80
81         atomic_set(&cred->uc_count, 0);
82         cred->uc_flags = RPCAUTH_CRED_UPTODATE;
83         if (flags & RPC_TASK_ROOTCREDS) {
84                 cred->uc_uid = cred->uc_puid = 0;
85                 cred->uc_gid = cred->uc_pgid = 0;
86                 cred->uc_xid = cred->uc_pxid = current->xid;
87                 cred->uc_gids[0] = NOGROUP;
88         } else {
89                 int groups = acred->group_info->ngroups;
90                 if (groups > NFS_NGROUPS)
91                         groups = NFS_NGROUPS;
92
93                 cred->uc_uid = acred->uid;
94                 cred->uc_gid = acred->gid;
95                 cred->uc_xid = acred->xid;
96                 cred->uc_puid = current->uid;
97                 cred->uc_pgid = current->gid;
98                 cred->uc_pxid = current->xid;
99                 for (i = 0; i < groups; i++)
100                         cred->uc_gids[i] = GROUP_AT(acred->group_info, i);
101                 if (i < NFS_NGROUPS)
102                   cred->uc_gids[i] = NOGROUP;
103         }
104         cred->uc_base.cr_ops = &unix_credops;
105
106         return (struct rpc_cred *) cred;
107 }
108
109 static void
110 unx_destroy_cred(struct rpc_cred *cred)
111 {
112         kfree(cred);
113 }
114
115 /*
116  * Match credentials against current process creds.
117  * The root_override argument takes care of cases where the caller may
118  * request root creds (e.g. for NFS swapping).
119  */
120 static int
121 unx_match(struct auth_cred *acred, struct rpc_cred *rcred, int taskflags)
122 {
123         struct unx_cred *cred = (struct unx_cred *) rcred;
124         int             i;
125
126         if (!(taskflags & RPC_TASK_ROOTCREDS)) {
127                 int groups;
128
129                 if (cred->uc_uid != acred->uid
130                  || cred->uc_gid != acred->gid
131                  || cred->uc_xid != acred->xid
132                  || cred->uc_puid != current->uid
133                  || cred->uc_pgid != current->gid
134                  || cred->uc_pxid != current->xid)
135                         return 0;
136
137                 groups = acred->group_info->ngroups;
138                 if (groups > NFS_NGROUPS)
139                         groups = NFS_NGROUPS;
140                 for (i = 0; i < groups ; i++)
141                         if (cred->uc_gids[i] != GROUP_AT(acred->group_info, i))
142                                 return 0;
143                 return 1;
144         }
145         return (cred->uc_uid == 0 && cred->uc_puid == 0
146              && cred->uc_gid == 0 && cred->uc_pgid == 0
147              && cred->uc_gids[0] == (gid_t) NOGROUP);
148 }
149
150 /*
151  * Marshal credentials.
152  * Maybe we should keep a cached credential for performance reasons.
153  */
154 static u32 *
155 unx_marshal(struct rpc_task *task, u32 *p, int ruid)
156 {
157         struct rpc_clnt *clnt = task->tk_client;
158         struct unx_cred *cred = (struct unx_cred *) task->tk_msg.rpc_cred;
159         u32             *base, *hold;
160         int             i, tagxid;
161
162         *p++ = htonl(RPC_AUTH_UNIX);
163         base = p++;
164         *p++ = htonl(jiffies/HZ);
165
166         /*
167          * Copy the UTS nodename captured when the client was created.
168          */
169         p = xdr_encode_array(p, clnt->cl_nodename, clnt->cl_nodelen);
170         tagxid = task->tk_client->cl_tagxid;
171
172         /* Note: we don't use real uid if it involves raising privilege */
173         if (ruid && cred->uc_puid != 0 && cred->uc_pgid != 0) {
174                 *p++ = htonl((u32) XIDINO_UID(tagxid,
175                         cred->uc_puid, cred->uc_pxid));
176                 *p++ = htonl((u32) XIDINO_GID(tagxid,
177                         cred->uc_pgid, cred->uc_pxid));
178         } else {
179                 *p++ = htonl((u32) XIDINO_UID(tagxid,
180                         cred->uc_uid, cred->uc_xid));
181                 *p++ = htonl((u32) XIDINO_GID(tagxid,
182                         cred->uc_gid, cred->uc_xid));
183         }
184         hold = p++;
185         for (i = 0; i < 16 && cred->uc_gids[i] != (gid_t) NOGROUP; i++)
186                 *p++ = htonl((u32) cred->uc_gids[i]);
187         *hold = htonl(p - hold - 1);            /* gid array length */
188         *base = htonl((p - base - 1) << 2);     /* cred length */
189
190         *p++ = htonl(RPC_AUTH_NULL);
191         *p++ = htonl(0);
192
193         return p;
194 }
195
196 /*
197  * Refresh credentials. This is a no-op for AUTH_UNIX
198  */
199 static int
200 unx_refresh(struct rpc_task *task)
201 {
202         task->tk_msg.rpc_cred->cr_flags |= RPCAUTH_CRED_UPTODATE;
203         return task->tk_status = -EACCES;
204 }
205
206 static u32 *
207 unx_validate(struct rpc_task *task, u32 *p)
208 {
209         rpc_authflavor_t        flavor;
210         u32                     size;
211
212         flavor = ntohl(*p++);
213         if (flavor != RPC_AUTH_NULL &&
214             flavor != RPC_AUTH_UNIX &&
215             flavor != RPC_AUTH_SHORT) {
216                 printk("RPC: bad verf flavor: %u\n", flavor);
217                 return NULL;
218         }
219
220         size = ntohl(*p++);
221         if (size > RPC_MAX_AUTH_SIZE) {
222                 printk("RPC: giant verf size: %u\n", size);
223                 return NULL;
224         }
225         task->tk_auth->au_rslack = (size >> 2) + 2;
226         p += (size >> 2);
227
228         return p;
229 }
230
231 struct rpc_authops      authunix_ops = {
232         .owner          = THIS_MODULE,
233         .au_flavor      = RPC_AUTH_UNIX,
234 #ifdef RPC_DEBUG
235         .au_name        = "UNIX",
236 #endif
237         .create         = unx_create,
238         .destroy        = unx_destroy,
239         .crcreate       = unx_create_cred,
240 };
241
242 static
243 struct rpc_credops      unix_credops = {
244         .crdestroy      = unx_destroy_cred,
245         .crmatch        = unx_match,
246         .crmarshal      = unx_marshal,
247         .crrefresh      = unx_refresh,
248         .crvalidate     = unx_validate,
249 };