Hello, I found the reason why "refuse options" is ignored on the server side. When then 5th argument (int val) in the poptOption struct is set to zero, the parsing function poptGetNextOpt() just continues with the next arg, without returning. So check_refuse_options() is simply not called in such cases. The attached patch makes "refuse options" work with checksum and compress. These are the most obvious options the server admin may want to reject. Well, there may be others. Best wishes, -- fabrice -------------- next part -------------- --- rsync-2.6.0.orig/options.c 2003-12-30 19:16:25.000000000 +0100 +++ rsync-2.6.0/options.c 2004-02-20 23:21:42.000000000 +0100 @@ -296,7 +296,7 @@ enum {OPT_VERSION = 1000, OPT_SENDER, OPT_EXCLUDE, OPT_EXCLUDE_FROM, OPT_DELETE_AFTER, OPT_DELETE_EXCLUDED, OPT_LINK_DEST, OPT_INCLUDE, OPT_INCLUDE_FROM, OPT_MODIFY_WINDOW, - OPT_READ_BATCH, OPT_WRITE_BATCH}; + OPT_READ_BATCH, OPT_WRITE_BATCH, OPT_CHECKSUM, OPT_COMPRESS}; static struct poptOption long_options[] = { /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */ @@ -336,7 +336,7 @@ {"group", 'g', POPT_ARG_NONE, &preserve_gid, 0, 0, 0 }, {"devices", 'D', POPT_ARG_NONE, &preserve_devices, 0, 0, 0 }, {"times", 't', POPT_ARG_NONE, &preserve_times, 0, 0, 0 }, - {"checksum", 'c', POPT_ARG_NONE, &always_checksum, 0, 0, 0 }, + {"checksum", 'c', POPT_ARG_NONE, &always_checksum, OPT_CHECKSUM, 0, 0 }, {"verbose", 'v', POPT_ARG_NONE, 0, 'v', 0, 0 }, {"quiet", 'q', POPT_ARG_NONE, 0, 'q', 0, 0 }, {"archive", 'a', POPT_ARG_NONE, &archive_mode, 0, 0, 0 }, @@ -353,7 +353,7 @@ {"compare-dest", 0, POPT_ARG_STRING, &compare_dest, 0, 0, 0 }, {"link-dest", 0, POPT_ARG_STRING, 0, OPT_LINK_DEST, 0, 0 }, /* TODO: Should this take an optional int giving the compression level? */ - {"compress", 'z', POPT_ARG_NONE, &do_compression, 0, 0, 0 }, + {"compress", 'z', POPT_ARG_NONE, &do_compression, OPT_COMPRESS, 0, 0 }, {"daemon", 0, POPT_ARG_NONE, &am_daemon, 0, 0, 0 }, {"no-detach", 0, POPT_ARG_NONE, &no_detach, 0, 0, 0 }, {"stats", 0, POPT_ARG_NONE, &do_stats, 0, 0, 0 }, @@ -585,6 +585,10 @@ #endif + case OPT_CHECKSUM: + case OPT_COMPRESS: + break; + default: /* FIXME: If --daemon is specified, then errors for later * parameters seem to disappear. */
On Fri, Feb 20, 2004 at 11:56:59PM +0100, Fabrice Bellet wrote:> I found the reason why "refuse options" is ignored on the server > side. When then 5th argument (int val) in the poptOption struct is > set to zero, the parsing function poptGetNextOpt() just continues > with the next arg, without returning.Good catch! I took a look at this code, and figured out a better way to implement the functionality that will let the user refuse any option in the list. The patch is attached. Unfortunately, the error message that gets generated by this failure doesn't get back to the user because of the wacky mode the daemon socket is in at the point these options are parsed. But that's a fix for another time. ..wayne.. -------------- next part -------------- --- options.c 11 Feb 2004 04:30:41 -0000 1.136 +++ options.c 21 Feb 2004 06:21:41 -0000 @@ -303,7 +303,7 @@ void usage(enum logcode F) enum {OPT_VERSION = 1000, OPT_SENDER, OPT_EXCLUDE, OPT_EXCLUDE_FROM, OPT_DELETE_AFTER, OPT_DELETE_EXCLUDED, OPT_LINK_DEST, OPT_INCLUDE, OPT_INCLUDE_FROM, OPT_MODIFY_WINDOW, - OPT_READ_BATCH, OPT_WRITE_BATCH}; + OPT_READ_BATCH, OPT_WRITE_BATCH, OPT_REFUSE_OPTION}; static struct poptOption long_options[] = { /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */ @@ -414,35 +414,28 @@ void option_error(void) /** - * Check to see if we should refuse this option + * Tweak the option table to disable all options that the rsyncd.conf + * file has told us to refuse. **/ -static int check_refuse_options(char *ref, int opt) +static void set_refuse_options(char *bp) { - int i, len; - char *p; - const char *name; + struct poptOption *opt; + char *cp; - for (i = 0; long_options[i].longName; i++) { - if (long_options[i].val == opt) - break; - } - - if (!long_options[i].longName) - return 0; - - name = long_options[i].longName; - len = strlen(name); - - while ((p = strstr(ref,name))) { - if ((p==ref || p[-1]==' ') && - (p[len] == ' ' || p[len] == 0)) { - snprintf(err_buf, sizeof err_buf, - "The '%s' option is not supported by this server\n", name); - return 1; + while (1) { + if ((cp = strchr(bp, ' ')) != NULL) + *cp= '\0'; + for (opt = long_options; opt->longName; opt++) { + if (strcmp(bp, opt->longName) == 0) { + opt->val = OPT_REFUSE_OPTION; + break; + } } - ref += len; + if (!cp) + break; + *cp = ' '; + bp = cp + 1; } - return 0; } @@ -471,6 +464,9 @@ int parse_arguments(int *argc, const cha char *ref = lp_refuse_options(module_id); poptContext pc; + if (ref && *ref) + set_refuse_options(ref); + /* TODO: Call poptReadDefaultConfig; handle errors. */ /* The context leaks in case of an error, but if there's a @@ -478,9 +474,6 @@ int parse_arguments(int *argc, const cha pc = poptGetContext(RSYNC_NAME, *argc, *argv, long_options, 0); while ((opt = poptGetNextOpt(pc)) != -1) { - if (ref && check_refuse_options(ref, opt)) - return 0; - /* most options are handled automatically by popt; * only special cases are returned and listed here. */ @@ -577,6 +570,19 @@ int parse_arguments(int *argc, const cha return 0; #endif + case OPT_REFUSE_OPTION: { + const char *op = poptBadOption(pc, POPT_BADOPTION_NOALIAS); + if (*op == '-' && op[1] == '-') { + snprintf(err_buf, sizeof err_buf, + "The '%s' option is not supported by this server\n", + op); + } else { + snprintf(err_buf, sizeof err_buf, + "One option in '%s' is not supported by this server\n", + op); + } + return 0; + } default: snprintf(err_buf, sizeof err_buf,