Whamcloud - gitweb
some minor changes in lsd upcall.
[fs/lustre-release.git] / lustre / utils / lsd_upcall.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  *  Copyright (C) 2004 Cluster File Systems, Inc.
5  *
6  *   This file is part of Lustre, http://www.lustre.org.
7  *
8  *   Lustre is free software; you can redistribute it and/or
9  *   modify it under the terms of version 2 of the GNU General Public
10  *   License as published by the Free Software Foundation.
11  *
12  *   Lustre is distributed in the hope that it will be useful,
13  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *   GNU General Public License for more details.
16  *
17  *   You should have received a copy of the GNU General Public License
18  *   along with Lustre; if not, write to the Free Software
19  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20  *
21  */
22
23 #include <stdlib.h>
24 #include <stdint.h>
25 #include <stdio.h>
26 #include <unistd.h>
27 #include <errno.h>
28 #include <string.h>
29 #include <fcntl.h>
30 #include <pwd.h>
31 #include <grp.h>
32
33 #include <liblustre.h>
34 #include <linux/lustre_idl.h>
35 #include <linux/obd.h>
36 #include <linux/lustre_mds.h>
37
38 #include <portals/types.h>
39 #include <portals/ptlctl.h>
40
41 /*
42  * return:
43  *  0:      fail to insert (found identical)
44  *  1:      inserted
45  */
46 int insert_sort(gid_t *groups, int size, gid_t grp)
47 {
48         int i;
49         gid_t save;
50
51         for (i = 0; i < size; i++) {
52                 if (groups[i] == grp)
53                         return 0;
54                 if (groups[i] > grp)
55                         break;
56         }
57
58         for (; i <= size; i++) {
59                 save = groups[i];
60                 groups[i] = grp;
61                 grp = save;
62         }
63         return 1;
64 }
65
66 int get_groups_local(uid_t uid, gid_t *gid, int *ngroups, gid_t **groups)
67 {
68         int     maxgroups;
69         int     i, size = 0;
70         struct passwd *pw;
71         struct group  *gr;
72
73         *ngroups = 0;
74         *groups = NULL;
75         maxgroups = sysconf(_SC_NGROUPS_MAX);
76         *groups = malloc(maxgroups * sizeof(gid_t));
77         if (!*groups)
78                 return -ENOMEM;
79
80         pw = getpwuid(uid);
81         if (!pw)
82                 return -ENOENT;
83
84         *gid = pw->pw_gid;
85
86         while ((gr = getgrent())) {
87                 if (!gr->gr_mem)
88                         continue;
89                 for (i = 0; gr->gr_mem[i]; i++) {
90                         if (strcmp(gr->gr_mem[i], pw->pw_name))
91                                 continue;
92                         size += insert_sort(*groups, size, gr->gr_gid);
93                         break;
94                 }
95                 if (size == maxgroups)
96                         break;
97         }
98         endgrent();
99         *ngroups = size;
100         return 0;
101 }
102
103 #define LINEBUF_SIZE    (1024)
104 static char linebuf[LINEBUF_SIZE];
105
106 int readline(FILE *fp, char *buf, int bufsize)
107 {
108         char *p = buf;
109         int i = 0;
110
111         if (fgets(buf, bufsize, fp) == NULL)
112                 return -1;
113
114         while (*p) {
115                 if (*p == '#') {
116                         *p = '\0';
117                         break;
118                 }
119                 if (*p == '\n') {
120                         *p = '\0';
121                         break;
122                 }
123                 i++;
124                 p++;
125         }
126
127         return i;
128 }
129
130 #define IS_SPACE(c) ((c) == ' ' || (c) == '\t')
131
132 void remove_space_head(char **buf)
133 {
134         char *p = *buf;
135
136         while (IS_SPACE(*p))
137                 p++;
138
139         *buf = p;
140 }
141
142 void remove_space_tail(char **buf)
143 {
144         char *p = *buf;
145         char *spc = NULL;
146
147         while (*p) {
148                 if (!IS_SPACE(*p)) {
149                         if (spc) spc = NULL;
150                 } else
151                         if (!spc) spc = p;
152                 p++;
153         }
154
155         if (spc)
156                 *spc = '\0';
157 }
158
159 int get_next_uid_range(char **buf, uid_t *uid_range)
160 {
161         char *p = *buf;
162         char *comma, *sub;
163
164         remove_space_head(&p);
165         if (strlen(p) == 0)
166                 return -1;
167
168         comma = strchr(p, ',');
169         if (comma) {
170                 *comma = '\0';
171                 *buf = comma + 1;
172         } else
173                 *buf = p + strlen(p);
174
175         sub = strchr(p, '-');
176         if (!sub) {
177                 uid_range[0] = uid_range[1] = atoi(p);
178         } else {
179                 *sub++ = '\0';
180                 uid_range[0] = atoi(p);
181                 uid_range[1] = atoi(sub);
182         }
183
184         return 0;
185 }
186
187 /*
188  * return 0: ok
189  */
190 int remove_bracket(char **buf)
191 {
192         char *p = *buf;
193         char *p2;
194
195         if (*p++ != '[')
196                 return -1;
197
198         p2 = strchr(p, ']');
199         if (!p2)
200                 return -1;
201
202         *p2++ = '\0';
203         while (*p2) {
204                 if (*p2 != ' ' && *p2 != '\t')
205                         return -1;
206                 p2++;
207         }
208
209         remove_space_tail(&p);
210         *buf = p;
211         return 0;
212 }
213
214 /* return 0: found a match */
215 int search_uid(FILE *fp, uid_t uid)
216 {
217         char *p;
218         uid_t uid_range[2];
219         int rc;
220
221         while (1) {
222                 rc = readline(fp, linebuf, LINEBUF_SIZE);
223                 if (rc < 0)
224                         return rc;
225                 if (rc == 0)
226                         continue;
227
228                 p = linebuf;
229                 if (remove_bracket(&p))
230                         continue;
231
232                 while (get_next_uid_range(&p, uid_range) == 0) {
233                         if (uid >= uid_range[0] && uid <= uid_range[1]) {
234                                 return 0;
235                         }
236                 }
237                 continue;
238         }
239 }
240
241 static struct {
242         char   *name;
243         __u32   bit;
244 } perm_types[] =  {
245         {"setuid",      LSD_PERM_SETUID},
246         {"setgid",      LSD_PERM_SETGID},
247         {"setgrp",      LSD_PERM_SETGRP},
248 };
249 #define N_PERM_TYPES    (3)
250
251 int parse_perm(__u32 *perm, char *str)
252 {
253         char *p = str;
254         char *comma;
255         int i;
256
257         *perm = 0;
258
259         while (1) {
260                 p = str;
261                 comma = strchr(str, ',');
262                 if (comma) {
263                         *comma = '\0';
264                         str = comma + 1;
265                 }
266
267                 for (i = 0; i < N_PERM_TYPES; i++) {
268                         if (!strcasecmp(p, perm_types[i].name)) {
269                                 *perm |= perm_types[i].bit;
270                                 break;
271                         }
272                 }
273
274                 if (i >= N_PERM_TYPES) {
275                         printf("unkown perm type: %s\n", p);
276                         return -1;
277                 }
278
279                 if (!comma)
280                         break;
281         }
282         return 0;
283 }
284
285 int parse_nid(ptl_nid_t *nidp, char *nid_str)
286 {
287         if (!strcmp(nid_str, "*")) {
288                 *nidp = PTL_NID_ANY;
289                 return 0;
290         }
291
292         return ptl_parse_nid(nidp, nid_str);
293 }
294
295 int get_one_perm(FILE *fp, struct lsd_permission *perm)
296 {
297         char nid_str[256], perm_str[256];
298         int rc;
299
300 again:
301         rc = readline(fp, linebuf, LINEBUF_SIZE);
302         if (rc < 0)
303                 return rc;
304         if (rc == 0)
305                 goto again;
306
307         rc = sscanf(linebuf, "%s %s", nid_str, perm_str);
308         if (rc != 2)
309                 return -1;
310
311         if (parse_nid(&perm->nid, nid_str))
312                 return -1;
313
314         if (parse_perm(&perm->perm, perm_str))
315                 return -1;
316
317         perm->netid = 0;
318         return 0;
319 }
320
321 #define MAX_PERMS       (50)
322
323 int get_perms(FILE *fp, uid_t uid, int *nperms, struct lsd_permission **perms)
324 {
325         static struct lsd_permission _perms[MAX_PERMS];
326
327         if (search_uid(fp, uid))
328                 return -1;
329
330         *nperms = 0;
331         while (*nperms < MAX_PERMS) {
332                 if (get_one_perm(fp, &_perms[*nperms]))
333                         break;
334                 (*nperms)++;
335         }
336         *perms = _perms;
337         return 0;
338 }
339
340 void show_result(struct lsd_downcall_args *dc)
341 {
342         int i;
343
344         printf("err: %d, uid %u, gid %d\n"
345                "ngroups: %d\n",
346                dc->err, dc->uid, dc->gid, dc->ngroups);
347         for (i = 0; i < dc->ngroups; i++)
348                 printf("\t%d\n", dc->groups[i]);
349
350         printf("nperms: %d\n", dc->nperms);
351         for (i = 0; i < dc->nperms; i++)
352                 printf("\t: netid %u, nid "LPX64", bits %x\n", i,
353                         dc->perms[i].nid, dc->perms[i].perm);
354 }
355
356 void usage(char *prog)
357 {
358         printf("Usage: %s [-t] uid\n", prog);
359         exit(1);
360 }
361
362 int main (int argc, char **argv)
363 {
364         char   *dc_name = "/proc/fs/lustre/mds/lsd_downcall";
365         int     dc_fd;
366         char   *conf_name = "/etc/lustre/lsd.conf";
367         FILE   *conf_fp;
368         struct lsd_downcall_args ioc_data;
369         extern char *optarg;
370         int     opt, testing = 0, rc;
371
372         while ((opt = getopt(argc, argv, "t")) != -1) {
373                 switch (opt) {
374                 case 't':
375                         testing = 1;
376                         break;
377                 default:
378                         usage(argv[0]);
379                 }
380         }
381
382         if (optind >= argc)
383                 usage(argv[0]);
384
385         memset(&ioc_data, 0, sizeof(ioc_data));
386         ioc_data.uid = atoi(argv[optind]);
387
388         /* read user/group database */
389         ioc_data.err = get_groups_local(ioc_data.uid, &ioc_data.gid,
390                                         (int *)&ioc_data.ngroups,
391                                         &ioc_data.groups);
392         if (ioc_data.err)
393                 goto do_downcall;
394
395         /* read lsd config database */
396         conf_fp = fopen(conf_name, "r");
397         if (conf_fp) {
398                 get_perms(conf_fp, ioc_data.uid,
399                           (int *)&ioc_data.nperms,
400                           &ioc_data.perms);
401                 fclose(conf_fp);
402         }
403
404
405 do_downcall:
406         if (testing) {
407                 show_result(&ioc_data);
408                 return 0;
409         } else {
410                 dc_fd = open(dc_name, O_WRONLY);
411                 if (dc_fd < 0) {
412                         printf("can't open device %s\n", dc_name);
413                         return -errno;
414                 }
415
416                 rc = write(dc_fd, &ioc_data, sizeof(ioc_data));
417                 return (rc != sizeof(ioc_data));
418         }
419 }