On Sun, Feb 12, 2023 at 09:16:58PM +0000, Job Snijders wrote:
> I noticed there is an issue in openrsync when a port is specified in the
> rsync:// URL, the port number ends up becoming part of the path:
> 
>     $ openrsync -r rsync://rsync.roa.tohunet.com:3873/repo/ /tmp/r
>     rsync: [sender] change_dir "/3873/repo" (in repo) failed: No such file or 
> directory (2)
> 
> The below changeset seems to improve the situation, but might not be the
> best way to fix it. I found fargs_parse() a bit hard to understand.

No kidding...

> OK? Suggestions?
> 
> Kind regards,
> 
> Job
> 
> Index: main.c
> ===================================================================
> RCS file: /cvs/src/usr.bin/rsync/main.c,v
> retrieving revision 1.65
> diff -u -p -r1.65 main.c
> --- main.c    2 Aug 2022 20:01:12 -0000       1.65
> +++ main.c    12 Feb 2023 21:06:00 -0000
> @@ -233,8 +233,12 @@ fargs_parse(size_t argc, char *argv[], s
>                   strncasecmp(cp, "rsync://", 8) == 0) {
>                       /* rsync://path */
>                       cp += 8;
> -                     if ((ccp = strchr(cp, ':')))    /* skip :port */
> +                     /* skip :port */
> +                     if ((ccp = strchr(cp, ':')) != NULL) {
>                               *ccp = '\0';
> +                             while (cp[len] != '/' && len < j)
> +                                     len++;
> +                     }

There are various issues here. First, you don't know that cp[len] is in
any way related to the location of ':' in the string since the strncmp()
only happens later.

This is equivalent to your while loop but starting at what we know to be
after the colon:

                                len += strcspn(ccp + 1, "/") + 1;

This brings me to the next problem: we must not modify len, as it is
the length of f->host. If there are multiple sources, len my grow and
eventually cp[len] could access out of bounds.

While it is not super clean, the easiest fix for this would be to do

                        /* rsync://path[:host] */
                        size_t save_len = len;

after the strncasecmp() above, then after the memmove() at the end of the
scope reset the length to what it originally was:

                        len = save_len;
                        
A bit cleaner would be to replace uses of len with

                        /* rsync://path[:host] */
                        size_t module_offset = len;

                        ...

                                module_offset += strcspn(ccp + 1, "/") + 1;

then replace all uses of len in this scope *after* the strncmp below with
module_offset.

>                       if (strncmp(cp, f->host, len) ||
>                           (cp[len] != '/' && cp[len] != '\0'))
>                               errx(ERR_SYNTAX, "different remote host: %s",
> 

Reply via email to