glusterfs

Форк
0
407 строк · 9.4 Кб
1
/*
2
   Copyright (c) 2011-2012 Red Hat, Inc. <http://www.redhat.com>
3
   This file is part of GlusterFS.
4

5
   This file is licensed to you under your choice of the GNU Lesser
6
   General Public License, version 3 or any later version (LGPLv3 or
7
   later), or the GNU General Public License, version 2 (GPLv2), in all
8
   cases as published by the Free Software Foundation.
9
*/
10
#include <glusterfs/compat.h>
11
#include <glusterfs/syscall.h>
12

13
#include <stdio.h>
14
#include <stdlib.h>
15
#include <string.h>
16
#include <sys/param.h> /* for PATH_MAX */
17
#include <unistd.h>
18

19
/* NOTE (USE_LIBGLUSTERFS):
20
 * ------------------------
21
 * When USE_LIBGLUSTERFS debugging sumbol is passed; perform
22
 * glusterfs translator like initialization so that glusterfs
23
 * globals, contexts are valid when glustefs api's are invoked.
24
 * We unconditionally pass then while building gsyncd binary.
25
 */
26
#ifdef USE_LIBGLUSTERFS
27
#include <glusterfs/defaults.h>
28
#include <glusterfs/globals.h>
29
#endif
30

31
#include "procdiggy.h"
32
#include <glusterfs/run.h>
33

34
#define _GLUSTERD_CALLED_ "_GLUSTERD_CALLED_"
35
#define _GSYNCD_DISPATCHED_ "_GSYNCD_DISPATCHED_"
36
#define GSYNCD_CONF_TEMPLATE "geo-replication/gsyncd_template.conf"
37
#define GSYNCD_PY "gsyncd.py"
38
#define RSYNC "rsync"
39

40
int restricted = 0;
41

42
static int
43
duplexpand(void **buf, size_t tsiz, size_t *len)
44
{
45
    size_t osiz = tsiz * *len;
46
    char *p = realloc(*buf, osiz << 1);
47
    if (!p) {
48
        return -1;
49
    }
50

51
    memset(p + osiz, 0, osiz);
52
    *buf = p;
53
    *len <<= 1;
54

55
    return 0;
56
}
57

58
static int
59
str2argv(char *str, char ***argv)
60
{
61
    char *p = NULL;
62
    char *savetok = NULL;
63
    char *temp = NULL;
64
    char *temp1 = NULL;
65
    int argc = 0;
66
    size_t argv_len = 32;
67
    int ret = 0;
68
    int i = 0;
69

70
    assert(str);
71
    temp = str = strdup(str);
72
    if (!str)
73
        goto error;
74

75
    *argv = calloc(argv_len, sizeof(**argv));
76
    if (!*argv)
77
        goto error;
78

79
    while ((p = strtok_r(str, " ", &savetok))) {
80
        str = NULL;
81

82
        argc++;
83
        if (argc == argv_len) {
84
            ret = duplexpand((void *)argv, sizeof(**argv), &argv_len);
85
            if (ret == -1)
86
                goto error;
87
        }
88
        temp1 = strdup(p);
89
        if (!temp1)
90
            goto error;
91
        (*argv)[argc - 1] = temp1;
92
    }
93

94
    free(temp);
95
    return argc;
96

97
error:
98
    fprintf(stderr, "out of memory\n");
99
    free(temp);
100
    for (i = 0; i < argc - 1; i++)
101
        free((*argv)[i]);
102
    free(*argv);
103
    return -1;
104
}
105

106
static int
107
invoke_gsyncd(int argc, char **argv)
108
{
109
    int i = 0;
110
    int j = 0;
111
    char *nargv[argc + 4];
112
    char *python = NULL;
113

114
    if (chdir("/") == -1)
115
        goto error;
116

117
    j = 0;
118
    python = getenv("PYTHON");
119
    if (!python)
120
        python = PYTHON;
121
    nargv[j++] = python;
122
    nargv[j++] = GSYNCD_PREFIX "/python/syncdaemon/" GSYNCD_PY;
123
    for (i = 1; i < argc; i++)
124
        nargv[j++] = argv[i];
125

126
    nargv[j++] = NULL;
127

128
    execvp(python, nargv);
129

130
    fprintf(stderr, "exec of '%s' failed\n", python);
131
    return 127;
132

133
error:
134
    fprintf(stderr, "gsyncd initializaion failed\n");
135
    return 1;
136
}
137

138
static int
139
find_gsyncd(pid_t pid, pid_t ppid, char *name, void *data)
140
{
141
    char buf[NAME_MAX * 2] = {
142
        0,
143
    };
144
    char path[PATH_MAX] = {
145
        0,
146
    };
147
    char *p = NULL;
148
    int zeros = 0;
149
    int ret = 0;
150
    int fd = -1;
151
    pid_t *pida = (pid_t *)data;
152

153
    if (ppid != pida[0])
154
        return 0;
155

156
    snprintf(path, sizeof path, PROC "/%d/cmdline", pid);
157
    fd = open(path, O_RDONLY);
158
    if (fd == -1)
159
        return 0;
160
    ret = sys_read(fd, buf, sizeof(buf));
161
    sys_close(fd);
162
    if (ret == -1)
163
        return 0;
164
    for (zeros = 0, p = buf; zeros < 2 && p < buf + ret; p++)
165
        zeros += !*p;
166

167
    ret = 0;
168
    switch (zeros) {
169
        case 2:
170
            if ((strcmp(basename(buf), basename(PYTHON)) ||
171
                 strcmp(basename(buf + strlen(buf) + 1), GSYNCD_PY)) == 0) {
172
                ret = 1;
173
                break;
174
            }
175
            /* fallthrough */
176
        case 1:
177
            if (strcmp(basename(buf), GSYNCD_PY) == 0)
178
                ret = 1;
179
    }
180

181
    if (ret == 1) {
182
        if (pida[1] != -1) {
183
            fprintf(stderr, GSYNCD_PY " sibling is not unique");
184
            return -1;
185
        }
186
        pida[1] = pid;
187
    }
188

189
    return 0;
190
}
191

192
static int
193
invoke_rsync(int argc, char **argv)
194
{
195
    int i = 0;
196
    char path[PATH_MAX] = {
197
        0,
198
    };
199
    pid_t pid = -1;
200
    pid_t ppid = -1;
201
    pid_t pida[] = {-1, -1};
202
    char *name = NULL;
203
    char buf[PATH_MAX + 1] = {
204
        0,
205
    };
206
    int ret = 0;
207

208
    assert(argv[argc] == NULL);
209

210
    if (argc < 2 || strcmp(argv[1], "--server") != 0)
211
        goto error;
212

213
    for (i = 2; i < argc && argv[i][0] == '-'; i++)
214
        ;
215

216
    if (!(i == argc - 2 && strcmp(argv[i], ".") == 0 &&
217
          argv[i + 1][0] == '/')) {
218
        fprintf(stderr, "need an rsync invocation without protected args\n");
219
        goto error;
220
    }
221

222
    /* look up sshd we are spawned from */
223
    for (pid = getpid();; pid = ppid) {
224
        ppid = pidinfo(pid, &name);
225
        if (ppid < 0) {
226
            fprintf(stderr, "sshd ancestor not found\n");
227
            goto error;
228
        }
229
        if (strcmp(name, "sshd") == 0) {
230
            GF_FREE(name);
231
            break;
232
        }
233
        GF_FREE(name);
234
    }
235
    /* look up "ssh-sibling" gsyncd */
236
    pida[0] = pid;
237
    ret = prociter(find_gsyncd, pida);
238
    if (ret == -1 || pida[1] == -1) {
239
        fprintf(stderr, "gsyncd sibling not found\n");
240
        goto error;
241
    }
242
    /* check if rsync target matches gsyncd target */
243
    snprintf(path, sizeof path, PROC "/%d/cwd", pida[1]);
244
    ret = sys_readlink(path, buf, sizeof(buf));
245
    if (ret == -1 || ret == sizeof(buf))
246
        goto error;
247

248
    buf[ret] = '\0';
249

250
    if (strcmp(argv[argc - 1], "/") == 0 /* root dir cannot be a target */ ||
251
        (strcmp(argv[argc - 1], path) /* match against gluster target */ &&
252
         strcmp(argv[argc - 1], buf) /* match against file target */) != 0) {
253
        fprintf(stderr, "rsync target does not match " GEOREP " session\n");
254
        goto error;
255
    }
256

257
    argv[0] = RSYNC;
258

259
    execvp(RSYNC, argv);
260

261
    fprintf(stderr, "exec of " RSYNC " failed\n");
262
    return 127;
263

264
error:
265
    fprintf(stderr, "disallowed " RSYNC " invocation\n");
266
    return 1;
267
}
268

269
static int
270
invoke_gluster(int argc, char **argv)
271
{
272
    int i = 0;
273
    int j = 0;
274
    int optsover = 0;
275
    char *ov = NULL;
276

277
    for (i = 1; i < argc; i++) {
278
        ov = strtail(argv[i], "--");
279
        if (ov && !optsover) {
280
            if (*ov == '\0')
281
                optsover = 1;
282
            continue;
283
        }
284
        switch (++j) {
285
            case 1:
286
                if (strcmp(argv[i], "volume") != 0)
287
                    goto error;
288
                break;
289
            case 2:
290
                if (strcmp(argv[i], "info") != 0)
291
                    goto error;
292
                break;
293
            case 3:
294
                break;
295
            default:
296
                goto error;
297
        }
298
    }
299

300
    argv[0] = SBIN_DIR "/gluster";
301
    execv(SBIN_DIR "/gluster", argv);
302
    fprintf(stderr, "exec of gluster failed\n");
303
    return 127;
304

305
error:
306
    fprintf(stderr, "disallowed gluster invocation\n");
307
    return 1;
308
}
309

310
struct invocable {
311
    char *name;
312
    int (*invoker)(int argc, char **argv);
313
};
314

315
struct invocable invocables[] = {{"rsync", invoke_rsync},
316
                                 {"gsyncd", invoke_gsyncd},
317
                                 {"gluster", invoke_gluster},
318
                                 {NULL, NULL}};
319

320
int
321
main(int argc, char **argv)
322
{
323
    int ret = -1;
324
    char *evas = NULL;
325
    struct invocable *i = NULL;
326
    char *b = NULL;
327
    char *sargv = NULL;
328
    int j = 0;
329

330
#ifdef USE_LIBGLUSTERFS
331
    glusterfs_ctx_t *ctx = NULL;
332

333
    ctx = glusterfs_ctx_new();
334
    if (!ctx)
335
        return ENOMEM;
336

337
    if (glusterfs_globals_init(ctx))
338
        return 1;
339

340
    THIS->ctx = ctx;
341
    ret = default_mem_acct_init(THIS);
342
    if (ret) {
343
        fprintf(stderr, "internal error: mem accounting failed\n");
344
        return 1;
345
    }
346
#endif
347

348
    evas = getenv(_GLUSTERD_CALLED_);
349
    if (evas && strcmp(evas, "1") == 0)
350
        /* OK, we know glusterd called us, no need to look for further config
351
         *...although this conclusion should not inherit to our children
352
         */
353
        unsetenv(_GLUSTERD_CALLED_);
354
    else {
355
        /* we regard all gsyncd invocations unsafe
356
         * that do not come from glusterd and
357
         * therefore restrict it
358
         */
359
        restricted = 1;
360

361
        if (!getenv(_GSYNCD_DISPATCHED_)) {
362
            evas = getenv("SSH_ORIGINAL_COMMAND");
363
            if (evas)
364
                sargv = evas;
365
            else {
366
                evas = getenv("SHELL");
367
                if (evas && strcmp(basename(evas), "gsyncd") == 0 &&
368
                    argc == 3 && strcmp(argv[1], "-c") == 0)
369
                    sargv = argv[2];
370
            }
371
        }
372
    }
373

374
    if (!(sargv && restricted))
375
        return invoke_gsyncd(argc, argv);
376

377
    argc = str2argv(sargv, &argv);
378

379
    if (argc == -1) {
380
        fprintf(stderr, "internal error\n");
381
        return 1;
382
    }
383

384
    if (setenv(_GSYNCD_DISPATCHED_, "1", 1) == -1) {
385
        fprintf(stderr, "internal error\n");
386
        goto out;
387
    }
388

389
    if ( argc >= 1 )
390
        b = basename(argv[0]);
391
    else
392
        goto out;
393

394
    for (i = invocables; i->name; i++) {
395
        if (strcmp(b, i->name) == 0)
396
            return i->invoker(argc, argv);
397
    }
398

399
    fprintf(stderr, "invoking %s in restricted SSH session is not allowed\n",
400
            b);
401

402
out:
403
    for (j = 1; j < argc; j++)
404
        free(argv[j]);
405
    free(argv);
406
    return 1;
407
}
408

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.