"Fossies" - the Fresh Open Source Software Archive

Member "glusterfs-8.2/geo-replication/src/gsyncd.c" (16 Sep 2020, 9573 Bytes) of package /linux/misc/glusterfs-8.2.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "gsyncd.c" see the Fossies "Dox" file reference documentation.

    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 <stdlib.h>
   14 #include <stdio.h>
   15 #include <unistd.h>
   16 #include <string.h>
   17 #include <sys/param.h> /* for PATH_MAX */
   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/glusterfs.h>
   28 #include <glusterfs/globals.h>
   29 #include <glusterfs/defaults.h>
   30 #endif
   31 
   32 #include <glusterfs/common-utils.h>
   33 #include <glusterfs/run.h>
   34 #include "procdiggy.h"
   35 
   36 #define _GLUSTERD_CALLED_ "_GLUSTERD_CALLED_"
   37 #define _GSYNCD_DISPATCHED_ "_GSYNCD_DISPATCHED_"
   38 #define GSYNCD_CONF_TEMPLATE "geo-replication/gsyncd_template.conf"
   39 #define GSYNCD_PY "gsyncd.py"
   40 #define RSYNC "rsync"
   41 
   42 int restricted = 0;
   43 
   44 static int
   45 duplexpand(void **buf, size_t tsiz, size_t *len)
   46 {
   47     size_t osiz = tsiz * *len;
   48     char *p = realloc(*buf, osiz << 1);
   49     if (!p) {
   50         return -1;
   51     }
   52 
   53     memset(p + osiz, 0, osiz);
   54     *buf = p;
   55     *len <<= 1;
   56 
   57     return 0;
   58 }
   59 
   60 static int
   61 str2argv(char *str, char ***argv)
   62 {
   63     char *p = NULL;
   64     char *savetok = NULL;
   65     char *temp = NULL;
   66     char *temp1 = NULL;
   67     int argc = 0;
   68     size_t argv_len = 32;
   69     int ret = 0;
   70     int i = 0;
   71 
   72     assert(str);
   73     temp = str = strdup(str);
   74     if (!str)
   75         goto error;
   76 
   77     *argv = calloc(argv_len, sizeof(**argv));
   78     if (!*argv)
   79         goto error;
   80 
   81     while ((p = strtok_r(str, " ", &savetok))) {
   82         str = NULL;
   83 
   84         argc++;
   85         if (argc == argv_len) {
   86             ret = duplexpand((void *)argv, sizeof(**argv), &argv_len);
   87             if (ret == -1)
   88                 goto error;
   89         }
   90         temp1 = strdup(p);
   91         if (!temp1)
   92             goto error;
   93         (*argv)[argc - 1] = temp1;
   94     }
   95 
   96     free(temp);
   97     return argc;
   98 
   99 error:
  100     fprintf(stderr, "out of memory\n");
  101     free(temp);
  102     for (i = 0; i < argc - 1; i++)
  103         free((*argv)[i]);
  104     free(*argv);
  105     return -1;
  106 }
  107 
  108 static int
  109 invoke_gsyncd(int argc, char **argv)
  110 {
  111     int i = 0;
  112     int j = 0;
  113     char *nargv[argc + 4];
  114     char *python = NULL;
  115 
  116     if (chdir("/") == -1)
  117         goto error;
  118 
  119     j = 0;
  120     python = getenv("PYTHON");
  121     if (!python)
  122         python = PYTHON;
  123     nargv[j++] = python;
  124     nargv[j++] = GSYNCD_PREFIX "/python/syncdaemon/" GSYNCD_PY;
  125     for (i = 1; i < argc; i++)
  126         nargv[j++] = argv[i];
  127 
  128     nargv[j++] = NULL;
  129 
  130     execvp(python, nargv);
  131 
  132     fprintf(stderr, "exec of '%s' failed\n", python);
  133     return 127;
  134 
  135 error:
  136     fprintf(stderr, "gsyncd initializaion failed\n");
  137     return 1;
  138 }
  139 
  140 static int
  141 find_gsyncd(pid_t pid, pid_t ppid, char *name, void *data)
  142 {
  143     char buf[NAME_MAX * 2] = {
  144         0,
  145     };
  146     char path[PATH_MAX] = {
  147         0,
  148     };
  149     char *p = NULL;
  150     int zeros = 0;
  151     int ret = 0;
  152     int fd = -1;
  153     pid_t *pida = (pid_t *)data;
  154 
  155     if (ppid != pida[0])
  156         return 0;
  157 
  158     snprintf(path, sizeof path, PROC "/%d/cmdline", pid);
  159     fd = open(path, O_RDONLY);
  160     if (fd == -1)
  161         return 0;
  162     ret = sys_read(fd, buf, sizeof(buf));
  163     sys_close(fd);
  164     if (ret == -1)
  165         return 0;
  166     for (zeros = 0, p = buf; zeros < 2 && p < buf + ret; p++)
  167         zeros += !*p;
  168 
  169     ret = 0;
  170     switch (zeros) {
  171         case 2:
  172             if ((strcmp(basename(buf), basename(PYTHON)) ||
  173                  strcmp(basename(buf + strlen(buf) + 1), GSYNCD_PY)) == 0) {
  174                 ret = 1;
  175                 break;
  176             }
  177             /* fallthrough */
  178         case 1:
  179             if (strcmp(basename(buf), GSYNCD_PY) == 0)
  180                 ret = 1;
  181     }
  182 
  183     if (ret == 1) {
  184         if (pida[1] != -1) {
  185             fprintf(stderr, GSYNCD_PY " sibling is not unique");
  186             return -1;
  187         }
  188         pida[1] = pid;
  189     }
  190 
  191     return 0;
  192 }
  193 
  194 static int
  195 invoke_rsync(int argc, char **argv)
  196 {
  197     int i = 0;
  198     char path[PATH_MAX] = {
  199         0,
  200     };
  201     pid_t pid = -1;
  202     pid_t ppid = -1;
  203     pid_t pida[] = {-1, -1};
  204     char *name = NULL;
  205     char buf[PATH_MAX + 1] = {
  206         0,
  207     };
  208     int ret = 0;
  209 
  210     assert(argv[argc] == NULL);
  211 
  212     if (argc < 2 || strcmp(argv[1], "--server") != 0)
  213         goto error;
  214 
  215     for (i = 2; i < argc && argv[i][0] == '-'; i++)
  216         ;
  217 
  218     if (!(i == argc - 2 && strcmp(argv[i], ".") == 0 &&
  219           argv[i + 1][0] == '/')) {
  220         fprintf(stderr, "need an rsync invocation without protected args\n");
  221         goto error;
  222     }
  223 
  224     /* look up sshd we are spawned from */
  225     for (pid = getpid();; pid = ppid) {
  226         ppid = pidinfo(pid, &name);
  227         if (ppid < 0) {
  228             fprintf(stderr, "sshd ancestor not found\n");
  229             goto error;
  230         }
  231         if (strcmp(name, "sshd") == 0) {
  232             GF_FREE(name);
  233             break;
  234         }
  235         GF_FREE(name);
  236     }
  237     /* look up "ssh-sibling" gsyncd */
  238     pida[0] = pid;
  239     ret = prociter(find_gsyncd, pida);
  240     if (ret == -1 || pida[1] == -1) {
  241         fprintf(stderr, "gsyncd sibling not found\n");
  242         goto error;
  243     }
  244     /* check if rsync target matches gsyncd target */
  245     snprintf(path, sizeof path, PROC "/%d/cwd", pida[1]);
  246     ret = sys_readlink(path, buf, sizeof(buf));
  247     if (ret == -1 || ret == sizeof(buf))
  248         goto error;
  249     if (strcmp(argv[argc - 1], "/") == 0 /* root dir cannot be a target */ ||
  250         (strcmp(argv[argc - 1], path) /* match against gluster target */ &&
  251          strcmp(argv[argc - 1], buf) /* match against file target */) != 0) {
  252         fprintf(stderr, "rsync target does not match " GEOREP " session\n");
  253         goto error;
  254     }
  255 
  256     argv[0] = RSYNC;
  257 
  258     execvp(RSYNC, argv);
  259 
  260     fprintf(stderr, "exec of " RSYNC " failed\n");
  261     return 127;
  262 
  263 error:
  264     fprintf(stderr, "disallowed " RSYNC " invocation\n");
  265     return 1;
  266 }
  267 
  268 static int
  269 invoke_gluster(int argc, char **argv)
  270 {
  271     int i = 0;
  272     int j = 0;
  273     int optsover = 0;
  274     char *ov = NULL;
  275 
  276     for (i = 1; i < argc; i++) {
  277         ov = strtail(argv[i], "--");
  278         if (ov && !optsover) {
  279             if (*ov == '\0')
  280                 optsover = 1;
  281             continue;
  282         }
  283         switch (++j) {
  284             case 1:
  285                 if (strcmp(argv[i], "volume") != 0)
  286                     goto error;
  287                 break;
  288             case 2:
  289                 if (strcmp(argv[i], "info") != 0)
  290                     goto error;
  291                 break;
  292             case 3:
  293                 break;
  294             default:
  295                 goto error;
  296         }
  297     }
  298 
  299     argv[0] = "gluster";
  300     execvp(SBIN_DIR "/gluster", argv);
  301     fprintf(stderr, "exec of gluster failed\n");
  302     return 127;
  303 
  304 error:
  305     fprintf(stderr, "disallowed gluster invocation\n");
  306     return 1;
  307 }
  308 
  309 struct invocable {
  310     char *name;
  311     int (*invoker)(int argc, char **argv);
  312 };
  313 
  314 struct invocable invocables[] = {{"rsync", invoke_rsync},
  315                                  {"gsyncd", invoke_gsyncd},
  316                                  {"gluster", invoke_gluster},
  317                                  {NULL, NULL}};
  318 
  319 int
  320 main(int argc, char **argv)
  321 {
  322     int ret = -1;
  323     char *evas = NULL;
  324     struct invocable *i = NULL;
  325     char *b = NULL;
  326     char *sargv = NULL;
  327     int j = 0;
  328 
  329 #ifdef USE_LIBGLUSTERFS
  330     glusterfs_ctx_t *ctx = NULL;
  331 
  332     ctx = glusterfs_ctx_new();
  333     if (!ctx)
  334         return ENOMEM;
  335 
  336     if (glusterfs_globals_init(ctx))
  337         return 1;
  338 
  339     THIS->ctx = ctx;
  340     ret = default_mem_acct_init(THIS);
  341     if (ret) {
  342         fprintf(stderr, "internal error: mem accounting failed\n");
  343         return 1;
  344     }
  345 #endif
  346 
  347     evas = getenv(_GLUSTERD_CALLED_);
  348     if (evas && strcmp(evas, "1") == 0)
  349         /* OK, we know glusterd called us, no need to look for further config
  350          *...although this conclusion should not inherit to our children
  351          */
  352         unsetenv(_GLUSTERD_CALLED_);
  353     else {
  354         /* we regard all gsyncd invocations unsafe
  355          * that do not come from glusterd and
  356          * therefore restrict it
  357          */
  358         restricted = 1;
  359 
  360         if (!getenv(_GSYNCD_DISPATCHED_)) {
  361             evas = getenv("SSH_ORIGINAL_COMMAND");
  362             if (evas)
  363                 sargv = evas;
  364             else {
  365                 evas = getenv("SHELL");
  366                 if (evas && strcmp(basename(evas), "gsyncd") == 0 &&
  367                     argc == 3 && strcmp(argv[1], "-c") == 0)
  368                     sargv = argv[2];
  369             }
  370         }
  371     }
  372 
  373     if (!(sargv && restricted))
  374         return invoke_gsyncd(argc, argv);
  375 
  376     argc = str2argv(sargv, &argv);
  377 
  378     if (argc == -1) {
  379         fprintf(stderr, "internal error\n");
  380         return 1;
  381     }
  382 
  383     if (setenv(_GSYNCD_DISPATCHED_, "1", 1) == -1) {
  384         fprintf(stderr, "internal error\n");
  385         goto out;
  386     }
  387 
  388     b = basename(argv[0]);
  389     for (i = invocables; i->name; i++) {
  390         if (strcmp(b, i->name) == 0)
  391             return i->invoker(argc, argv);
  392     }
  393 
  394     fprintf(stderr, "invoking %s in restricted SSH session is not allowed\n",
  395             b);
  396 
  397 out:
  398     for (j = 1; j < argc; j++)
  399         free(argv[j]);
  400     free(argv);
  401     return 1;
  402 }