1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2 * vim:expandtab:shiftwidth=8:tabstop=8:
4 * Copyright (C) 2005 Cluster File Systems, Inc.
6 * This file is part of Lustre, http://www.lustre.org.
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.
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.
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.
23 #include <sys/types.h>
36 #include <liblustre.h>
37 #include <linux/lustre_idl.h>
38 #include <linux/obd.h>
39 #include <linux/lustre_mds.h>
40 #include <linux/obd_support.h>
42 #include <portals/ptlctl.h>
43 #include <portals/types.h>
45 static int g_testing = 0;
47 #define log_msg(fmt, args...) \
50 printf(fmt, ## args); \
52 syslog(LOG_ERR, fmt, ## args); \
55 int switch_user_identity(uid_t uid)
59 int maxgroups, ngroups = 0;
64 /* originally must be root */
65 if (getuid() != 0 || geteuid() != 0) {
66 log_msg("non-root: %u/%u\n", getuid(), geteuid());
70 /* nothing more is needed for root */
78 maxgroups = sysconf(_SC_NGROUPS_MAX);
79 groups = malloc(maxgroups * sizeof(gid_t));
81 log_msg("memory alloc failure\n");
87 log_msg("no such uid %u\n", uid);
93 while ((gr = getgrent())) {
96 for (i = 0; gr->gr_mem[i]; i++) {
97 if (strcmp(gr->gr_mem[i], pw->pw_name))
99 groups[ngroups++] = gr->gr_gid;
102 if (ngroups == maxgroups)
107 if (setgroups(ngroups, groups) == -1) {
108 log_msg("set %d groups: %s\n", ngroups, strerror(errno));
114 if (setgid(gid) == -1) {
115 log_msg("setgid %u: %s\n", gid, strerror(errno));
119 if (setuid(uid) == -1) {
120 log_msg("setuid %u: %s\n", uid, strerror(errno));
128 * caller guarantee args not empty
130 int compose_command_line(char *cmdline, char *op, char *args)
132 char *p, *params, *file;
134 /* skip the white space at the tail */
135 p = args + strlen(args) - 1;
138 if (*p != ' ' && *p != '\t')
143 /* not allow empty args */
149 /* find next space */
151 if (*p == ' ' || *p == '\t')
158 file = p + 1; /* file name */
165 /* backward path not allowed */
166 if (strstr(file, ".."))
169 /* absolute path not allowed */
173 snprintf(cmdline, PATH_MAX, "%sfacl %s %s",
178 void do_acl_command(uid_t uid, char *lroot, char *cmdline)
180 if (switch_user_identity(uid)) {
181 printf("MDS: invalid user %u\n", uid);
185 if (chdir(lroot) < 0) {
186 log_msg("chdir to %s: %s\n", lroot, strerror(errno));
187 printf("MDS: can't change dir\n");
191 execl("/bin/sh", "sh", "-c", cmdline, NULL);
192 printf("MDS: can't execute\n");
195 #define ERRSTR_NO_CMDLINE "No command line supplied\n"
196 #define ERRSTR_INVALID_ARGS "Invalid arguments\n"
197 #define ERRSTR_MDS_PROCESS "MDS procession error\n"
200 * The args passed in are:
207 #define OUTPUT_BUFSIZE 8192
208 int main (int argc, char **argv)
210 struct rmtacl_downcall_args dc_args;
211 char *dc_name = "/proc/fs/lustre/mds/lacl_downcall";
214 char output[OUTPUT_BUFSIZE];
215 char cmdline[PATH_MAX];
216 int pipeout[2], pipeerr[2], pid;
217 int output_size, rd, childret;
220 log_msg("invalid argc %d\n", argc);
224 /* XXX temp for debugging */
225 log_msg("enter: %s %s %s %s %s\n",
226 argv[1], argv[2], argv[3], argv[4], argv[5]);
228 if (strcmp(argv[4], "get") && strcmp(argv[4], "set")) {
229 log_msg("invalid arg 4: %s\n", argv[4]);
233 dc_args.key = strtoull(argv[1], NULL, 16);
234 dc_args.res = output;
236 dc_args.status = -1; /* default return error */
240 if (strlen(argv[5]) == 0) {
241 dc_args.reslen = sizeof(ERRSTR_NO_CMDLINE);
242 memcpy(output, ERRSTR_NO_CMDLINE, dc_args.reslen);
246 if (compose_command_line(cmdline, argv[4], argv[5])) {
247 dc_args.reslen = sizeof(ERRSTR_INVALID_ARGS);
248 memcpy(output, ERRSTR_INVALID_ARGS, dc_args.reslen);
253 if (pipe(pipeout) < 0 || pipe(pipeerr) < 0) {
254 dc_args.reslen = sizeof(ERRSTR_MDS_PROCESS);
255 memcpy(output, ERRSTR_MDS_PROCESS, dc_args.reslen);
259 if ((pid = fork()) < 0) {
260 dc_args.reslen = sizeof(ERRSTR_MDS_PROCESS);
261 memcpy(output, ERRSTR_MDS_PROCESS, dc_args.reslen);
263 } else if (pid == 0) {
265 if (pipeout[1] != STDOUT_FILENO) {
266 dup2(pipeout[1], STDOUT_FILENO);
271 if (pipeerr[1] != STDERR_FILENO) {
272 dup2(pipeerr[1], STDERR_FILENO);
278 do_acl_command(uid, argv[3], cmdline);
282 /* parent process handling */
289 rd = read(pipeout[0], output + output_size,
290 OUTPUT_BUFSIZE - output_size);
292 output_size = sizeof(ERRSTR_MDS_PROCESS);
293 memcpy(output, ERRSTR_MDS_PROCESS, dc_args.reslen);
299 if (output_size >= OUTPUT_BUFSIZE)
303 /* if we got standard output, just leave; otherwise collect
306 if (output_size != 0)
310 rd = read(pipeerr[0], output + output_size,
311 OUTPUT_BUFSIZE - output_size);
313 output_size = sizeof(ERRSTR_MDS_PROCESS);
314 memcpy(output, ERRSTR_MDS_PROCESS, dc_args.reslen);
320 if (output_size >= OUTPUT_BUFSIZE)
327 dc_args.status = childret;
328 dc_args.reslen = output_size;
331 dc_fd = open(dc_name, O_WRONLY);
333 log_msg("can't open %s: %s\n", dc_name, strerror(errno));
337 rc = write(dc_fd, &dc_args, sizeof(dc_args));
338 if (rc != sizeof(dc_args))
339 log_msg("write error: ret %d\n", rc);
344 /* XXX temp for debugging */
345 log_msg("finished upcall\n");