/* * The socket based protocol for setting up a connection with rsyncd. * * Copyright (C) 1998-2001 Andrew Tridgell <tridge@samba.org> * Copyright (C) 2001-2002 Martin Pool <mbp@samba.org> * Copyright (C) 2002-2022 Wayne Davison * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, visit the http://fsf.org website. */ #include "rsync.h"#include "itypes.h"#include "ifuncs.h" extern int quiet;extern int dry_run;extern int output_motd;extern int list_only;extern int am_sender;extern int am_server;extern int am_daemon;extern int am_chrooted;extern int am_root;extern int msgs2stderr;extern int rsync_port;extern int protect_args;extern int ignore_errors;extern int preserve_xattrs;extern int kluge_around_eof;extern int munge_symlinks;extern int use_secure_symlinks;extern int open_noatime;extern int sanitize_paths;extern int daemon_config_filter_file;extern int numeric_ids;extern int filesfrom_fd;extern int remote_protocol;extern int protocol_version;extern int io_timeout;extern int no_detach;extern int write_batch;extern int old_style_args;extern int default_af_hint;extern int logfile_format_has_i;extern int logfile_format_has_o_or_i;extern char *bind_address;extern char *config_file;extern char *logfile_format;extern char *files_from;extern char *tmpdir;extern char *early_input_file;extern struct chmod_mode_struct *chmod_modes;extern filter_rule_list daemon_filter_list;#ifdef ICONV_OPTIONextern char *iconv_opt;extern iconv_t ic_send, ic_recv;#endifextern uid_t our_uid;extern gid_t our_gid; char *auth_user;char *daemon_auth_choices;/* read_args() enforces MAX_DAEMON_ARGS and reports "too many daemon arguments" * before a daemon client can grow argv without bound. */int read_only = 0;int module_id = -1;int pid_file_fd = -1;int early_input_len = 0;char *early_input = NULL;pid_t namecvt_pid = 0;struct chmod_mode_struct *daemon_chmod_modes; #define EARLY_INPUT_CMD "#early_input="#define EARLY_INPUT_CMDLEN (sizeof EARLY_INPUT_CMD - 1) /* Fallback bound on each peer-driven daemon handshake phase when no positive * "timeout" is configured. A module value can shorten the pre-auth and * argument-read phases, but cannot extend either beyond this limit. */#define DAEMON_HANDSHAKE_TIMEOUT 60 static int daemon_handshake_timeout(int module){ int timeout = lp_timeout(module); /* "timeout" is parsed with atoi(), so negative values are possible. */ if (timeout <= 0 || timeout > DAEMON_HANDSHAKE_TIMEOUT) timeout = DAEMON_HANDSHAKE_TIMEOUT; return timeout;} /* module_dirlen is the length of the module_dir string when in daemon * mode and module_dir is not "/"; otherwise 0. (Note that a chroot- * enabled module can have a non-"/" module_dir these days.) */char *module_dir = NULL;unsigned int module_dirlen = 0;/* An fd held open on the served module root, captured while the daemon is still * positioned there (and privileged) -- so the sender's directory scan can be * confined beneath the module by resolving module-relative paths against this fd, * without re-walking (and re-permission-checking) the absolute module path as the * dropped-privilege module uid. -1 when not a daemon or not yet captured. */int module_dirfd = -1; char *full_module_path; static int rl_nulls = 0;static int namecvt_fd_req = -1, namecvt_fd_ans = -1; #ifdef HAVE_SIGACTIONstatic struct sigaction sigact;#endif static item_list gid_list = EMPTY_ITEM_LIST; /* Used when "reverse lookup" is off. */const char undetermined_hostname[] = "UNDETERMINED"; /** * Run a client connected to an rsyncd. The alternative to this * function for remote-shell connections is do_cmd(). * * After negotiating which module to use and reading the server's * motd, this hands over to client_run(). Telling the server the * module will cause it to chroot/setuid/etc. * * Instead of doing a transfer, the client may at this stage instead * get a listing of remote modules and exit. * * @return -1 for error in startup, or the result of client_run(). * Either way, it eventually gets passed to exit_cleanup(). **/int start_socket_client(char *host, int remote_argc, char *remote_argv[], int argc, char *argv[]){ int fd, ret; char *p, *user = NULL; /* This is redundant with code in start_inband_exchange(), but this * short-circuits a problem in the client before we open a socket, * and the extra check won't hurt. */ if (**remote_argv == '/') { rprintf(FERROR, "ERROR: The remote path must start with a module name not a /\n"); return -1; } if ((p = strrchr(host, '@')) != NULL) { user = host; host = p+1; *p = '\0'; } fd = open_socket_out_wrapped(host, rsync_port, bind_address, default_af_hint); if (fd == -1) exit_cleanup(RERR_SOCKETIO); #ifdef ICONV_CONST setup_iconv();#endif ret = start_inband_exchange(fd, fd, user, remote_argc, remote_argv); return ret ? ret : client_run(fd, fd, -1, argc, argv);} static int exchange_protocols(int f_in, int f_out, char *buf, size_t bufsiz, int am_client){ int remote_sub = -1; int our_sub = get_subprotocol_version(); output_daemon_greeting(f_out, am_client); if (!am_client) { char *motd = lp_motd_file(); if (motd && *motd) { /* 'motd file = PATH': motd content is sent to every client, so * a planted symlink would leak the target's bytes. Refuse * symlinks not owned by uid 0 or our euid. */ int motd_fd = open_no_attacker_symlinks(motd, O_RDONLY, 0); FILE *f = motd_fd >= 0 ? fdopen(motd_fd, "r") : NULL; if (!f && motd_fd >= 0) close(motd_fd); while (f && !feof(f)) { int len = fread(buf, 1, bufsiz - 1, f); if (len > 0) write_buf(f_out, buf, len); } if (f) fclose(f); write_sbuf(f_out, "\n"); } } /* This strips the \n. */ if (!read_line_old(f_in, buf, bufsiz, 0)) { if (am_client) rprintf(FERROR, "rsync: did not see server greeting\n"); return -1; } if (sscanf(buf, "@RSYNCD: %d.%d", &remote_protocol, &remote_sub) < 1) { if (am_client) rprintf(FERROR, "rsync: server sent \"%s\" rather than greeting\n", buf); else io_printf(f_out, "@ERROR: protocol startup error\n"); return -1; } if (remote_sub < 0) { if (remote_protocol >= 30) { if (am_client) rprintf(FERROR, "rsync: the server omitted the subprotocol value: %s\n", buf); else io_printf(f_out, "@ERROR: your client omitted the subprotocol value: %s\n", buf); return -1; } remote_sub = 0; } daemon_auth_choices = strchr(buf + 9, ' '); if (daemon_auth_choices) { char *cp; daemon_auth_choices = strdup(daemon_auth_choices + 1); if ((cp = strchr(daemon_auth_choices, '\n')) != NULL) *cp = '\0'; } else if (remote_protocol > 31) { if (am_client) rprintf(FERROR, "rsync: the server omitted the digest name list: %s\n", buf); else io_printf(f_out, "@ERROR: your client omitted the digest name list: %s\n", buf); return -1; } if (protocol_version > remote_protocol) { protocol_version = remote_protocol; if (remote_sub) protocol_version--; } else if (protocol_version == remote_protocol) { if (remote_sub != our_sub) protocol_version--; }#if SUBPROTOCOL_VERSION != 0 else if (protocol_version < remote_protocol) { if (our_sub) protocol_version--; }#endif if (protocol_version >= 30) rl_nulls = 1; return 0;} int start_inband_exchange(int f_in, int f_out, const char *user, int argc, char *argv[]){ int i, modlen; char line[BIGPATHBUFLEN]; char *sargs[MAX_ARGS]; int sargc = 0; char *p, *modname; assert(argc > 0 && *argv != NULL); if (**argv == '/') { rprintf(FERROR, "ERROR: The remote path must start with a module name\n"); return -1; } if (!(p = strchr(*argv, '/'))) modlen = strlen(*argv); else modlen = p - *argv; modname = new_array(char, modlen+1+1); /* room for '/' & '\0' */ strlcpy(modname, *argv, modlen + 1); modname[modlen] = '/'; modname[modlen+1] = '\0'; if (!user) user = getenv("USER"); if (!user) user = getenv("LOGNAME"); if (exchange_protocols(f_in, f_out, line, sizeof line, 1) < 0) { free(modname); return -1; } if (early_input_file) { STRUCT_STAT st; /* --early-input-file=PATH: refuse symlinks not owned by uid 0 or * our euid anywhere in the path. */ int ei_fd = open_no_attacker_symlinks(early_input_file, O_RDONLY, 0); FILE *f = ei_fd >= 0 ? fdopen(ei_fd, "rb") : NULL; if (!f && ei_fd >= 0) close(ei_fd); if (!f || do_fstat(fileno(f), &st) < 0) { rsyserr(FERROR, errno, "failed to open %s", early_input_file); if (f) fclose(f); free(modname); return -1; } early_input_len = st.st_size; if (early_input_len > (int)sizeof line) { rprintf(FERROR, "%s is > %d bytes.\n", early_input_file, (int)sizeof line); fclose(f); free(modname); return -1; } if (early_input_len > 0) { io_printf(f_out, EARLY_INPUT_CMD "%d\n", early_input_len); while (early_input_len > 0) { int len; if (feof(f)) { rprintf(FERROR, "Early EOF in %s\n", early_input_file); fclose(f); free(modname); return -1; } len = fread(line, 1, early_input_len, f); if (len > 0) { write_buf(f_out, line, len); early_input_len -= len; } } } fclose(f); } server_options(sargs, &sargc); if (sargc >= MAX_ARGS - 2) goto arg_overflow; sargs[sargc++] = "."; if (!old_style_args) snprintf(line, sizeof line, " %.*s/", modlen, modname); while (argc > 0) { if (sargc >= MAX_ARGS - 1) { arg_overflow: rprintf(FERROR, "internal: args[] overflowed in do_cmd()\n"); exit_cleanup(RERR_SYNTAX); } if (strncmp(*argv, modname, modlen) == 0 && argv[0][modlen] == '\0') sargs[sargc++] = modname; /* we send "modname/" */ else { char *arg = *argv; int extra_chars = *arg == '-' ? 2 : 0; /* a leading dash needs a "./" prefix. */ /* If --old-args was not specified, make sure that the arg won't split at a mod name! */ if (!old_style_args && (p = strstr(arg, line)) != NULL) { do { extra_chars += 2; } while ((p = strstr(p+1, line)) != NULL); } if (extra_chars) { char *f = arg; char *t = arg = new_array(char, strlen(arg) + extra_chars + 1); if (*f == '-') { *t++ = '.'; *t++ = '/'; } while (*f) { if (*f == ' ' && strncmp(f, line, modlen+2) == 0) { *t++ = '['; *t++ = *f++; *t++ = ']'; } else *t++ = *f++; } *t = '\0'; } sargs[sargc++] = arg; } argv++; argc--; } sargs[sargc] = NULL; if (DEBUG_GTE(CMD, 1)) print_child_argv("sending daemon args:", sargs); io_printf(f_out, "%.*s\n", modlen, modname); /* Old servers may just drop the connection here, rather than sending a proper EXIT command. Yuck. */ kluge_around_eof = list_only && protocol_version < 25 ? 1 : 0; while (1) { if (!read_line_old(f_in, line, sizeof line, 0)) { rprintf(FERROR, "rsync: didn't get server startup line\n"); free(modname); return -1; } if (strncmp(line,"@RSYNCD: AUTHREQD ",18) == 0) { auth_client(f_out, user, line+18); continue; } if (strcmp(line,"@RSYNCD: OK") == 0) break; if (strcmp(line,"@RSYNCD: EXIT") == 0) { /* This is sent by recent versions of the * server to terminate the listing of modules. * We don't want to go on and transfer * anything; just exit. */ exit(0); } if (strncmp(line, "@ERROR", 6) == 0) { rprintf(FERROR, "%s\n", line); /* This is always fatal; the server will now * close the socket. */ free(modname); return -1; } /* This might be a MOTD line or a module listing, but there is * no way to differentiate it. The manpage mentions this. */ if (output_motd) rprintf(FINFO, "%s\n", line); } kluge_around_eof = 0; if (rl_nulls) { for (i = 0; i < sargc; i++) { if (!sargs[i]) /* stop at --secluded-args NULL */ break; write_sbuf(f_out, sargs[i]); write_byte(f_out, 0); } write_byte(f_out, 0); } else { for (i = 0; i < sargc; i++) io_printf(f_out, "%s\n", sargs[i]); write_sbuf(f_out, "\n"); } if (protect_args) send_protected_args(f_out, sargs); if (protocol_version < 23) { if (protocol_version == 22 || !am_sender) io_start_multiplex_in(f_in); } free(modname); return 0;} #if defined HAVE_SETENV || defined HAVE_PUTENVstatic int read_arg_from_pipe(int fd, char *buf, int limit){ char *bp = buf, *eob = buf + limit - 1; while (1) { int got = read(fd, bp, 1); if (got != 1) { if (got < 0 && errno == EINTR) continue; return -1; } if (*bp == '\0') break; if (bp < eob) bp++; } *bp = '\0'; return bp - buf;}#endif void set_env_str(const char *var, const char *str){#ifdef HAVE_SETENV if (setenv(var, str, 1) < 0) out_of_memory("set_env_str");#else#ifdef HAVE_PUTENV char *mem; if (asprintf(&mem, "%s=%s", var, str) < 0) out_of_memory("set_env_str"); putenv(mem);#elseLines 1–500 of 1799. Load more
/* * The socket based protocol for setting up a connection with rsyncd. * * Copyright (C) 1998-2001 Andrew Tridgell <tridge@samba.org> * Copyright (C) 2001-2002 Martin Pool <mbp@samba.org> * Copyright (C) 2002-2022 Wayne Davison * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, visit the http://fsf.org website. */ #include "rsync.h" #include "itypes.h" #include "ifuncs.h" extern int quiet; extern int dry_run; extern int output_motd; extern int list_only; extern int am_sender; extern int am_server; extern int am_daemon; extern int am_chrooted; extern int am_root; extern int msgs2stderr; extern int rsync_port; extern int protect_args; extern int ignore_errors; extern int preserve_xattrs; extern int kluge_around_eof; extern int munge_symlinks; extern int use_secure_symlinks; extern int open_noatime; extern int sanitize_paths; extern int daemon_config_filter_file; extern int numeric_ids; extern int filesfrom_fd; extern int remote_protocol; extern int protocol_version; extern int io_timeout; extern int no_detach; extern int write_batch; extern int old_style_args; extern int default_af_hint; extern int logfile_format_has_i; extern int logfile_format_has_o_or_i; extern char *bind_address; extern char *config_file; extern char *logfile_format; extern char *files_from; extern char *tmpdir; extern char *early_input_file; extern struct chmod_mode_struct *chmod_modes; extern filter_rule_list daemon_filter_list; #ifdef ICONV_OPTION extern char *iconv_opt; extern iconv_t ic_send, ic_recv; #endif extern uid_t our_uid; extern gid_t our_gid; char *auth_user; char *daemon_auth_choices; /* read_args() enforces MAX_DAEMON_ARGS and reports "too many daemon arguments" * before a daemon client can grow argv without bound. */ int read_only = 0; int module_id = -1; int pid_file_fd = -1; int early_input_len = 0; char *early_input = NULL; pid_t namecvt_pid = 0; struct chmod_mode_struct *daemon_chmod_modes; #define EARLY_INPUT_CMD "#early_input=" #define EARLY_INPUT_CMDLEN (sizeof EARLY_INPUT_CMD - 1) /* Fallback bound on each peer-driven daemon handshake phase when no positive * "timeout" is configured. A module value can shorten the pre-auth and * argument-read phases, but cannot extend either beyond this limit. */ #define DAEMON_HANDSHAKE_TIMEOUT 60 static int daemon_handshake_timeout(int module) { int timeout = lp_timeout(module); /* "timeout" is parsed with atoi(), so negative values are possible. */ if (timeout <= 0 || timeout > DAEMON_HANDSHAKE_TIMEOUT) timeout = DAEMON_HANDSHAKE_TIMEOUT; return timeout; } /* module_dirlen is the length of the module_dir string when in daemon * mode and module_dir is not "/"; otherwise 0. (Note that a chroot- * enabled module can have a non-"/" module_dir these days.) */ char *module_dir = NULL; unsigned int module_dirlen = 0; /* An fd held open on the served module root, captured while the daemon is still * positioned there (and privileged) -- so the sender's directory scan can be * confined beneath the module by resolving module-relative paths against this fd, * without re-walking (and re-permission-checking) the absolute module path as the * dropped-privilege module uid. -1 when not a daemon or not yet captured. */ int module_dirfd = -1; char *full_module_path; static int rl_nulls = 0; static int namecvt_fd_req = -1, namecvt_fd_ans = -1; #ifdef HAVE_SIGACTION static struct sigaction sigact; #endif static item_list gid_list = EMPTY_ITEM_LIST; /* Used when "reverse lookup" is off. */ const char undetermined_hostname[] = "UNDETERMINED"; /** * Run a client connected to an rsyncd. The alternative to this * function for remote-shell connections is do_cmd(). * * After negotiating which module to use and reading the server's * motd, this hands over to client_run(). Telling the server the * module will cause it to chroot/setuid/etc. * * Instead of doing a transfer, the client may at this stage instead * get a listing of remote modules and exit. * * @return -1 for error in startup, or the result of client_run(). * Either way, it eventually gets passed to exit_cleanup(). **/ int start_socket_client(char *host, int remote_argc, char *remote_argv[], int argc, char *argv[]) { int fd, ret; char *p, *user = NULL; /* This is redundant with code in start_inband_exchange(), but this * short-circuits a problem in the client before we open a socket, * and the extra check won't hurt. */ if (**remote_argv == '/') { rprintf(FERROR, "ERROR: The remote path must start with a module name not a /\n"); return -1; } if ((p = strrchr(host, '@')) != NULL) { user = host; host = p+1; *p = '\0'; } fd = open_socket_out_wrapped(host, rsync_port, bind_address, default_af_hint); if (fd == -1) exit_cleanup(RERR_SOCKETIO); #ifdef ICONV_CONST setup_iconv(); #endif ret = start_inband_exchange(fd, fd, user, remote_argc, remote_argv); return ret ? ret : client_run(fd, fd, -1, argc, argv); } static int exchange_protocols(int f_in, int f_out, char *buf, size_t bufsiz, int am_client) { int remote_sub = -1; int our_sub = get_subprotocol_version(); output_daemon_greeting(f_out, am_client); if (!am_client) { char *motd = lp_motd_file(); if (motd && *motd) { /* 'motd file = PATH': motd content is sent to every client, so * a planted symlink would leak the target's bytes. Refuse * symlinks not owned by uid 0 or our euid. */ int motd_fd = open_no_attacker_symlinks(motd, O_RDONLY, 0); FILE *f = motd_fd >= 0 ? fdopen(motd_fd, "r") : NULL; if (!f && motd_fd >= 0) close(motd_fd); while (f && !feof(f)) { int len = fread(buf, 1, bufsiz - 1, f); if (len > 0) write_buf(f_out, buf, len); } if (f) fclose(f); write_sbuf(f_out, "\n"); } } /* This strips the \n. */ if (!read_line_old(f_in, buf, bufsiz, 0)) { if (am_client) rprintf(FERROR, "rsync: did not see server greeting\n"); return -1; } if (sscanf(buf, "@RSYNCD: %d.%d", &remote_protocol, &remote_sub) < 1) { if (am_client) rprintf(FERROR, "rsync: server sent \"%s\" rather than greeting\n", buf); else io_printf(f_out, "@ERROR: protocol startup error\n"); return -1; } if (remote_sub < 0) { if (remote_protocol >= 30) { if (am_client) rprintf(FERROR, "rsync: the server omitted the subprotocol value: %s\n", buf); else io_printf(f_out, "@ERROR: your client omitted the subprotocol value: %s\n", buf); return -1; } remote_sub = 0; } daemon_auth_choices = strchr(buf + 9, ' '); if (daemon_auth_choices) { char *cp; daemon_auth_choices = strdup(daemon_auth_choices + 1); if ((cp = strchr(daemon_auth_choices, '\n')) != NULL) *cp = '\0'; } else if (remote_protocol > 31) { if (am_client) rprintf(FERROR, "rsync: the server omitted the digest name list: %s\n", buf); else io_printf(f_out, "@ERROR: your client omitted the digest name list: %s\n", buf); return -1; } if (protocol_version > remote_protocol) { protocol_version = remote_protocol; if (remote_sub) protocol_version--; } else if (protocol_version == remote_protocol) { if (remote_sub != our_sub) protocol_version--; } #if SUBPROTOCOL_VERSION != 0 else if (protocol_version < remote_protocol) { if (our_sub) protocol_version--; } #endif if (protocol_version >= 30) rl_nulls = 1; return 0; } int start_inband_exchange(int f_in, int f_out, const char *user, int argc, char *argv[]) { int i, modlen; char line[BIGPATHBUFLEN]; char *sargs[MAX_ARGS]; int sargc = 0; char *p, *modname; assert(argc > 0 && *argv != NULL); if (**argv == '/') { rprintf(FERROR, "ERROR: The remote path must start with a module name\n"); return -1; } if (!(p = strchr(*argv, '/'))) modlen = strlen(*argv); else modlen = p - *argv; modname = new_array(char, modlen+1+1); /* room for '/' & '\0' */ strlcpy(modname, *argv, modlen + 1); modname[modlen] = '/'; modname[modlen+1] = '\0'; if (!user) user = getenv("USER"); if (!user) user = getenv("LOGNAME"); if (exchange_protocols(f_in, f_out, line, sizeof line, 1) < 0) { free(modname); return -1; } if (early_input_file) { STRUCT_STAT st; /* --early-input-file=PATH: refuse symlinks not owned by uid 0 or * our euid anywhere in the path. */ int ei_fd = open_no_attacker_symlinks(early_input_file, O_RDONLY, 0); FILE *f = ei_fd >= 0 ? fdopen(ei_fd, "rb") : NULL; if (!f && ei_fd >= 0) close(ei_fd); if (!f || do_fstat(fileno(f), &st) < 0) { rsyserr(FERROR, errno, "failed to open %s", early_input_file); if (f) fclose(f); free(modname); return -1; } early_input_len = st.st_size; if (early_input_len > (int)sizeof line) { rprintf(FERROR, "%s is > %d bytes.\n", early_input_file, (int)sizeof line); fclose(f); free(modname); return -1; } if (early_input_len > 0) { io_printf(f_out, EARLY_INPUT_CMD "%d\n", early_input_len); while (early_input_len > 0) { int len; if (feof(f)) { rprintf(FERROR, "Early EOF in %s\n", early_input_file); fclose(f); free(modname); return -1; } len = fread(line, 1, early_input_len, f); if (len > 0) { write_buf(f_out, line, len); early_input_len -= len; } } } fclose(f); } server_options(sargs, &sargc); if (sargc >= MAX_ARGS - 2) goto arg_overflow; sargs[sargc++] = "."; if (!old_style_args) snprintf(line, sizeof line, " %.*s/", modlen, modname); while (argc > 0) { if (sargc >= MAX_ARGS - 1) { arg_overflow: rprintf(FERROR, "internal: args[] overflowed in do_cmd()\n"); exit_cleanup(RERR_SYNTAX); } if (strncmp(*argv, modname, modlen) == 0 && argv[0][modlen] == '\0') sargs[sargc++] = modname; /* we send "modname/" */ else { char *arg = *argv; int extra_chars = *arg == '-' ? 2 : 0; /* a leading dash needs a "./" prefix. */ /* If --old-args was not specified, make sure that the arg won't split at a mod name! */ if (!old_style_args && (p = strstr(arg, line)) != NULL) { do { extra_chars += 2; } while ((p = strstr(p+1, line)) != NULL); } if (extra_chars) { char *f = arg; char *t = arg = new_array(char, strlen(arg) + extra_chars + 1); if (*f == '-') { *t++ = '.'; *t++ = '/'; } while (*f) { if (*f == ' ' && strncmp(f, line, modlen+2) == 0) { *t++ = '['; *t++ = *f++; *t++ = ']'; } else *t++ = *f++; } *t = '\0'; } sargs[sargc++] = arg; } argv++; argc--; } sargs[sargc] = NULL; if (DEBUG_GTE(CMD, 1)) print_child_argv("sending daemon args:", sargs); io_printf(f_out, "%.*s\n", modlen, modname); /* Old servers may just drop the connection here, rather than sending a proper EXIT command. Yuck. */ kluge_around_eof = list_only && protocol_version < 25 ? 1 : 0; while (1) { if (!read_line_old(f_in, line, sizeof line, 0)) { rprintf(FERROR, "rsync: didn't get server startup line\n"); free(modname); return -1; } if (strncmp(line,"@RSYNCD: AUTHREQD ",18) == 0) { auth_client(f_out, user, line+18); continue; } if (strcmp(line,"@RSYNCD: OK") == 0) break; if (strcmp(line,"@RSYNCD: EXIT") == 0) { /* This is sent by recent versions of the * server to terminate the listing of modules. * We don't want to go on and transfer * anything; just exit. */ exit(0); } if (strncmp(line, "@ERROR", 6) == 0) { rprintf(FERROR, "%s\n", line); /* This is always fatal; the server will now * close the socket. */ free(modname); return -1; } /* This might be a MOTD line or a module listing, but there is * no way to differentiate it. The manpage mentions this. */ if (output_motd) rprintf(FINFO, "%s\n", line); } kluge_around_eof = 0; if (rl_nulls) { for (i = 0; i < sargc; i++) { if (!sargs[i]) /* stop at --secluded-args NULL */ break; write_sbuf(f_out, sargs[i]); write_byte(f_out, 0); } write_byte(f_out, 0); } else { for (i = 0; i < sargc; i++) io_printf(f_out, "%s\n", sargs[i]); write_sbuf(f_out, "\n"); } if (protect_args) send_protected_args(f_out, sargs); if (protocol_version < 23) { if (protocol_version == 22 || !am_sender) io_start_multiplex_in(f_in); } free(modname); return 0; } #if defined HAVE_SETENV || defined HAVE_PUTENV static int read_arg_from_pipe(int fd, char *buf, int limit) { char *bp = buf, *eob = buf + limit - 1; while (1) { int got = read(fd, bp, 1); if (got != 1) { if (got < 0 && errno == EINTR) continue; return -1; } if (*bp == '\0') break; if (bp < eob) bp++; } *bp = '\0'; return bp - buf; } #endif void set_env_str(const char *var, const char *str) { #ifdef HAVE_SETENV if (setenv(var, str, 1) < 0) out_of_memory("set_env_str"); #else #ifdef HAVE_PUTENV char *mem; if (asprintf(&mem, "%s=%s", var, str) < 0) out_of_memory("set_env_str"); putenv(mem); #else