Whamcloud - gitweb
land b_colibri_devel on HEAD:
[fs/lustre-release.git] / lustre / mdt / mdt_identity.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  * Copyright (C) 2004-2006 Cluster File Systems, Inc.
5  *   Author: Lai Siyao <lsy@clusterfs.com>
6  *   Author: Fan Yong <fanyong@clusterfs.com>
7  *
8  *   This file is part of Lustre, http://www.lustre.org.
9  *
10  *   Lustre is free software; you can redistribute it and/or
11  *   modify it under the terms of version 2 of the GNU General Public
12  *   License as published by the Free Software Foundation.
13  *
14  *   Lustre is distributed in the hope that it will be useful,
15  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  *   GNU General Public License for more details.
18  *
19  *   You should have received a copy of the GNU General Public License
20  *   along with Lustre; if not, write to the Free Software
21  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22  */
23
24 #ifndef EXPORT_SYMTAB
25 #define EXPORT_SYMTAB
26 #endif
27 #define DEBUG_SUBSYSTEM S_MDS
28
29 #ifndef AUTOCONF_INCLUDED
30 #include <linux/config.h>
31 #endif
32 #include <linux/module.h>
33 #include <linux/kernel.h>
34 #include <linux/mm.h>
35 #include <linux/kmod.h>
36 #include <linux/string.h>
37 #include <linux/stat.h>
38 #include <linux/errno.h>
39 #include <linux/version.h>
40 #include <linux/unistd.h>
41 #include <asm/system.h>
42 #include <asm/uaccess.h>
43 #include <linux/fs.h>
44 #include <linux/stat.h>
45 #include <asm/uaccess.h>
46 #include <linux/slab.h>
47 #include <asm/segment.h>
48
49 #include <libcfs/kp30.h>
50 #include <obd.h>
51 #include <obd_class.h>
52 #include <obd_support.h>
53 #include <lustre_net.h>
54 #include <lustre_import.h>
55 #include <lustre_dlm.h>
56 #include <lustre_lib.h>
57 #include <lustre_ucache.h>
58
59 #include "mdt_internal.h"
60
61 static void mdt_identity_entry_init(struct upcall_cache_entry *entry,
62                                     void *unused)
63 {
64         entry->u.identity.mi_uc_entry = entry;
65 }
66
67 static void mdt_identity_entry_free(struct upcall_cache *cache,
68                                     struct upcall_cache_entry *entry)
69 {
70         struct md_identity *identity = &entry->u.identity;
71
72         if (identity->mi_ginfo) {
73                 groups_free(identity->mi_ginfo);
74                 identity->mi_ginfo = NULL;
75         }
76
77         if (identity->mi_nperms) {
78                 LASSERT(identity->mi_perms);
79                 OBD_FREE(identity->mi_perms,
80                          identity->mi_nperms * sizeof(struct md_perm));
81                 identity->mi_nperms = 0;
82         }
83 }
84
85 static int mdt_identity_do_upcall(struct upcall_cache *cache,
86                                   struct upcall_cache_entry *entry)
87 {
88         char keystr[16];
89         char *argv[] = {
90                   [0] = cache->uc_upcall,
91                   [1] = cache->uc_name,
92                   [2] = keystr,
93                   [3] = NULL
94         };
95         char *envp[] = {
96                   [0] = "HOME=/",
97                   [1] = "PATH=/sbin:/usr/sbin",
98                   [2] = NULL
99         };
100         int rc;
101         ENTRY;
102
103         snprintf(keystr, sizeof(keystr), LPU64, entry->ue_key);
104
105         LASSERTF(strcmp(cache->uc_upcall, "NONE"), "no upcall set!");
106         CDEBUG(D_INFO, "The upcall is: %s \n", cache->uc_upcall);
107
108         rc = USERMODEHELPER(argv[0], argv, envp);
109         if (rc < 0) {
110                 CERROR("%s: error invoking upcall %s %s %s: rc %d; "
111                        "check /proc/fs/lustre/mdt/%s/identity_upcall\n",
112                        cache->uc_name, argv[0], argv[1], argv[2], rc,
113                        cache->uc_name);
114         } else {
115                 CDEBUG(D_HA, "%s: invoked upcall %s %s %s\n", cache->uc_name,
116                        argv[0], argv[1], argv[2]);
117                 rc = 0;
118         }
119         RETURN(rc);
120 }
121
122 static int mdt_identity_parse_downcall(struct upcall_cache *cache,
123                                        struct upcall_cache_entry *entry,
124                                        void *args)
125 {
126         struct md_identity *identity = &entry->u.identity;
127         struct identity_downcall_data *data = args;
128         struct group_info *ginfo;
129         struct md_perm *perms = NULL;
130         int size, i;
131         ENTRY;
132
133         LASSERT(data);
134         if (data->idd_ngroups > NGROUPS_MAX)
135                 RETURN(-E2BIG);
136
137         ginfo = groups_alloc(data->idd_ngroups);
138         if (!ginfo) {
139                 CERROR("failed to alloc %d groups\n", data->idd_ngroups);
140                 RETURN(-ENOMEM);
141         }
142
143         lustre_groups_from_list(ginfo, data->idd_groups);
144         lustre_groups_sort(ginfo);
145
146         if (data->idd_nperms) {
147                 size = data->idd_nperms * sizeof(*perms);
148                 OBD_ALLOC(perms, size);
149                 if (!perms) {
150                         CERROR("failed to alloc %d permissions\n",
151                                data->idd_nperms);
152                         groups_free(ginfo);
153                         RETURN(-ENOMEM);
154                 }
155
156                 for (i = 0; i < data->idd_nperms; i++) {
157                         perms[i].mp_nid = data->idd_perms[i].pdd_nid;
158                         perms[i].mp_perm = data->idd_perms[i].pdd_perm;
159                 }
160         }
161
162         identity->mi_uid = data->idd_uid;
163         identity->mi_gid = data->idd_gid;
164         identity->mi_ginfo = ginfo;
165         identity->mi_nperms = data->idd_nperms;
166         identity->mi_perms = perms;
167
168         CDEBUG(D_OTHER, "parse mdt identity@%p: %d:%d, ngroups %u, nperms %u\n",
169                identity, identity->mi_uid, identity->mi_gid,
170                identity->mi_ginfo->ngroups, identity->mi_nperms);
171
172         RETURN(0);
173 }
174
175 struct md_identity *mdt_identity_get(struct upcall_cache *cache, __u32 uid)
176 {
177         struct upcall_cache_entry *entry;
178
179         if (!cache)
180                 return NULL;
181
182         entry = upcall_cache_get_entry(cache, (__u64)uid, NULL);
183         if (IS_ERR(entry)) {
184                 CERROR("upcall_cache_get_entry failed: %ld\n", PTR_ERR(entry));
185                 return NULL;
186         }
187
188         return &entry->u.identity;
189 }
190
191 void mdt_identity_put(struct upcall_cache *cache, struct md_identity *identity)
192 {
193         if (!cache)
194                 return;
195
196         LASSERT(identity);
197         upcall_cache_put_entry(cache, identity->mi_uc_entry);
198 }
199
200 struct upcall_cache_ops mdt_identity_upcall_cache_ops = {
201         .init_entry     = mdt_identity_entry_init,
202         .free_entry     = mdt_identity_entry_free,
203         .do_upcall      = mdt_identity_do_upcall,
204         .parse_downcall = mdt_identity_parse_downcall,
205 };
206
207 void mdt_flush_identity(struct upcall_cache *cache, int uid)
208 {
209         if (uid < 0)
210                 upcall_cache_flush_idle(cache);
211         else
212                 upcall_cache_flush_one(cache, (__u64)uid, NULL);
213 }
214
215 /*
216  * If there is LNET_NID_ANY in perm[i].mp_nid,
217  * it must be perm[0].mp_nid, and act as default perm.
218  */
219 __u32 mdt_identity_get_perm(struct md_identity *identity,
220                                    __u32 is_rmtclient, lnet_nid_t nid)
221 {
222         struct md_perm *perm;
223         int i;
224
225         if (!identity) {
226                 LASSERT(is_rmtclient == 0);
227                 return CFS_SETGRP_PERM;
228         }
229
230         perm = identity->mi_perms;
231         /* check exactly matched nid first */
232         for (i = identity->mi_nperms - 1; i > 0; i--) {
233                 if (perm[i].mp_nid != nid)
234                         continue;
235                 return perm[i].mp_perm;
236         }
237
238         /* check LNET_NID_ANY then */
239         if ((identity->mi_nperms > 0) &&
240             ((perm[0].mp_nid == nid) || (perm[0].mp_nid == LNET_NID_ANY)))
241                 return perm[0].mp_perm;
242
243         /* return default last */
244         return is_rmtclient ? 0 : CFS_SETGRP_PERM;
245 }
246
247 int mdt_pack_remote_perm(struct mdt_thread_info *info, struct mdt_object *o,
248                          void *buf)
249 {
250         struct ptlrpc_request   *req = mdt_info_req(info);
251         struct md_ucred         *uc = mdt_ucred(info);
252         struct md_object        *next = mdt_object_child(o);
253         struct mdt_export_data  *med = mdt_req2med(req);
254         struct mdt_remote_perm  *perm = buf;
255
256         ENTRY;
257
258         /* remote client request always pack ptlrpc_user_desc! */
259         LASSERT(perm);
260
261         if (!med->med_rmtclient)
262                 RETURN(-EBADE);
263
264         if ((uc->mu_valid != UCRED_OLD) && (uc->mu_valid != UCRED_NEW))
265                 RETURN(-EINVAL);
266
267         perm->rp_uid = uc->mu_o_uid;
268         perm->rp_gid = uc->mu_o_gid;
269         perm->rp_fsuid = uc->mu_o_fsuid;
270         perm->rp_fsgid = uc->mu_o_fsgid;
271
272         perm->rp_access_perm = 0;
273         if (mo_permission(info->mti_env, NULL, next, NULL, MAY_READ) == 0)
274                 perm->rp_access_perm |= MAY_READ;
275         if (mo_permission(info->mti_env, NULL, next, NULL, MAY_WRITE) == 0)
276                 perm->rp_access_perm |= MAY_WRITE;
277         if (mo_permission(info->mti_env, NULL, next, NULL, MAY_EXEC) == 0)
278                 perm->rp_access_perm |= MAY_EXEC;
279
280         RETURN(0);
281 }