|
version 1.1.1.2, 2013/10/14 07:51:14
|
version 1.1.1.4, 2021/03/17 00:32:36
|
|
Line 3
|
Line 3
|
| * |
* |
| * Copyright (C) 1998-2001 Andrew Tridgell <tridge@samba.org> |
* Copyright (C) 1998-2001 Andrew Tridgell <tridge@samba.org> |
| * Copyright (C) 2001-2002 Martin Pool <mbp@samba.org> |
* Copyright (C) 2001-2002 Martin Pool <mbp@samba.org> |
| * Copyright (C) 2002-2013 Wayne Davison | * Copyright (C) 2002-2020 Wayne Davison |
| * |
* |
| * This program is free software; you can redistribute it and/or modify |
* 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 |
* it under the terms of the GNU General Public License as published by |
|
Line 21
|
Line 21
|
| |
|
| #include "rsync.h" |
#include "rsync.h" |
| #include "itypes.h" |
#include "itypes.h" |
| |
#include "ifuncs.h" |
| |
|
| extern int quiet; |
extern int quiet; |
| extern int dry_run; |
extern int dry_run; |
|
Line 30 extern int am_sender;
|
Line 31 extern int am_sender;
|
| extern int am_server; |
extern int am_server; |
| extern int am_daemon; |
extern int am_daemon; |
| extern int am_root; |
extern int am_root; |
| |
extern int msgs2stderr; |
| extern int rsync_port; |
extern int rsync_port; |
| extern int protect_args; |
extern int protect_args; |
| extern int ignore_errors; |
extern int ignore_errors; |
| extern int preserve_xattrs; |
extern int preserve_xattrs; |
| extern int kluge_around_eof; |
extern int kluge_around_eof; |
| extern int daemon_over_rsh; |
|
| extern int munge_symlinks; |
extern int munge_symlinks; |
| |
extern int open_noatime; |
| extern int sanitize_paths; |
extern int sanitize_paths; |
| extern int numeric_ids; |
extern int numeric_ids; |
| extern int filesfrom_fd; |
extern int filesfrom_fd; |
| extern int remote_protocol; |
extern int remote_protocol; |
| extern int protocol_version; |
extern int protocol_version; |
| |
extern int always_checksum; |
| |
extern int checksum_files; |
| extern int io_timeout; |
extern int io_timeout; |
| extern int no_detach; |
extern int no_detach; |
| extern int write_batch; |
extern int write_batch; |
|
Line 50 extern int logfile_format_has_i;
|
Line 54 extern int logfile_format_has_i;
|
| extern int logfile_format_has_o_or_i; |
extern int logfile_format_has_o_or_i; |
| extern char *bind_address; |
extern char *bind_address; |
| extern char *config_file; |
extern char *config_file; |
| |
extern char *link_by_hash_dir; |
| extern char *logfile_format; |
extern char *logfile_format; |
| extern char *files_from; |
extern char *files_from; |
| extern char *tmpdir; |
extern char *tmpdir; |
| |
extern char *early_input_file; |
| extern struct chmod_mode_struct *chmod_modes; |
extern struct chmod_mode_struct *chmod_modes; |
| extern filter_rule_list daemon_filter_list; |
extern filter_rule_list daemon_filter_list; |
| #ifdef ICONV_OPTION |
#ifdef ICONV_OPTION |
| extern char *iconv_opt; |
extern char *iconv_opt; |
| extern iconv_t ic_send, ic_recv; |
extern iconv_t ic_send, ic_recv; |
| #endif |
#endif |
| |
extern uid_t our_uid; |
| |
extern gid_t our_gid; |
| |
|
| #define MAX_GID_LIST 32 |
|
| |
|
| char *auth_user; |
char *auth_user; |
| int read_only = 0; |
int read_only = 0; |
| int module_id = -1; |
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; |
struct chmod_mode_struct *daemon_chmod_modes; |
| |
|
| |
#define EARLY_INPUT_CMD "#early_input=" |
| |
#define EARLY_INPUT_CMDLEN (sizeof EARLY_INPUT_CMD - 1) |
| |
|
| /* module_dirlen is the length of the module_dir string when in daemon |
/* 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- |
* mode and module_dir is not "/"; otherwise 0. (Note that a chroot- |
| * enabled module can have a non-"/" module_dir these days.) */ |
* enabled module can have a non-"/" module_dir these days.) */ |
|
Line 76 unsigned int module_dirlen = 0;
|
Line 89 unsigned int module_dirlen = 0;
|
| char *full_module_path; |
char *full_module_path; |
| |
|
| static int rl_nulls = 0; |
static int rl_nulls = 0; |
| |
static int namecvt_fd_req = -1, namecvt_fd_ans = -1; |
| |
|
| #ifdef HAVE_SIGACTION |
#ifdef HAVE_SIGACTION |
| static struct sigaction sigact; |
static struct sigaction sigact; |
| #endif |
#endif |
| |
|
| static gid_t gid_list[MAX_GID_LIST]; | static item_list gid_list = EMPTY_ITEM_LIST; |
| static int gid_count = 0; | |
| |
|
| /* Used when "reverse lookup" is off. */ |
/* Used when "reverse lookup" is off. */ |
| const char undetermined_hostname[] = "UNDETERMINED"; |
const char undetermined_hostname[] = "UNDETERMINED"; |
|
Line 122 int start_socket_client(char *host, int remote_argc, c
|
Line 135 int start_socket_client(char *host, int remote_argc, c
|
| *p = '\0'; |
*p = '\0'; |
| } |
} |
| |
|
| fd = open_socket_out_wrapped(host, rsync_port, bind_address, | fd = open_socket_out_wrapped(host, rsync_port, bind_address, default_af_hint); |
| default_af_hint); | |
| if (fd == -1) |
if (fd == -1) |
| exit_cleanup(RERR_SOCKETIO); |
exit_cleanup(RERR_SOCKETIO); |
| |
|
|
Line 131 int start_socket_client(char *host, int remote_argc, c
|
Line 143 int start_socket_client(char *host, int remote_argc, c
|
| setup_iconv(); |
setup_iconv(); |
| #endif |
#endif |
| |
|
| ret = start_inband_exchange(fd, fd, user, remote_argc, remote_argv); | ret = start_inband_exchange(fd, fd, user, host, remote_argc, remote_argv); |
| |
|
| return ret ? ret : client_run(fd, fd, -1, argc, argv); |
return ret ? ret : client_run(fd, fd, -1, argc, argv); |
| } |
} |
|
Line 144 static int exchange_protocols(int f_in, int f_out, cha
|
Line 156 static int exchange_protocols(int f_in, int f_out, cha
|
| #else |
#else |
| int our_sub = 0; |
int our_sub = 0; |
| #endif |
#endif |
| char *motd; |
|
| |
|
| io_printf(f_out, "@RSYNCD: %d.%d\n", protocol_version, our_sub); |
io_printf(f_out, "@RSYNCD: %d.%d\n", protocol_version, our_sub); |
| |
|
| if (!am_client) { |
if (!am_client) { |
| motd = lp_motd_file(); | char *motd = lp_motd_file(); |
| if (motd && *motd) { |
if (motd && *motd) { |
| FILE *f = fopen(motd,"r"); | FILE *f = fopen(motd, "r"); |
| while (f && !feof(f)) { |
while (f && !feof(f)) { |
| int len = fread(buf, 1, bufsiz - 1, f); |
int len = fread(buf, 1, bufsiz - 1, f); |
| if (len > 0) |
if (len > 0) |
|
Line 210 static int exchange_protocols(int f_in, int f_out, cha
|
Line 220 static int exchange_protocols(int f_in, int f_out, cha
|
| return 0; |
return 0; |
| } |
} |
| |
|
| int start_inband_exchange(int f_in, int f_out, const char *user, int argc, char *argv[]) | int start_inband_exchange(int f_in, int f_out, const char *user, const char *host, int argc, char *argv[]) |
| { |
{ |
| int i, modlen; |
int i, modlen; |
| char line[BIGPATHBUFLEN]; |
char line[BIGPATHBUFLEN]; |
|
Line 231 int start_inband_exchange(int f_in, int f_out, const c
|
Line 241 int start_inband_exchange(int f_in, int f_out, const c
|
| else |
else |
| modlen = p - *argv; |
modlen = p - *argv; |
| |
|
| if (!(modname = new_array(char, modlen+1+1))) /* room for '/' & '\0' */ | modname = new_array(char, modlen+1+1); /* room for '/' & '\0' */ |
| out_of_memory("start_inband_exchange"); | |
| strlcpy(modname, *argv, modlen + 1); |
strlcpy(modname, *argv, modlen + 1); |
| modname[modlen] = '/'; |
modname[modlen] = '/'; |
| modname[modlen+1] = '\0'; |
modname[modlen+1] = '\0'; |
|
Line 245 int start_inband_exchange(int f_in, int f_out, const c
|
Line 254 int start_inband_exchange(int f_in, int f_out, const c
|
| if (exchange_protocols(f_in, f_out, line, sizeof line, 1) < 0) |
if (exchange_protocols(f_in, f_out, line, sizeof line, 1) < 0) |
| return -1; |
return -1; |
| |
|
| /* set daemon_over_rsh to false since we need to build the | if (early_input_file) { |
| * true set of args passed through the rsh/ssh connection; | STRUCT_STAT st; |
| * this is a no-op for direct-socket-connection mode */ | FILE *f = fopen(early_input_file, "rb"); |
| daemon_over_rsh = 0; | if (!f || do_fstat(fileno(f), &st) < 0) { |
| | rsyserr(FERROR, errno, "failed to open %s", early_input_file); |
| | 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); |
| | 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); |
| | 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); |
server_options(sargs, &sargc); |
| |
|
| if (sargc >= MAX_ARGS - 2) |
if (sargc >= MAX_ARGS - 2) |
|
Line 296 int start_inband_exchange(int f_in, int f_out, const c
|
Line 331 int start_inband_exchange(int f_in, int f_out, const c
|
| continue; |
continue; |
| } |
} |
| |
|
| |
if (strcmp(line, "@RSYNCD: GSS") == 0) { |
| |
#ifdef GSSAPI_OPTION |
| |
if (auth_gss_client(f_out, host) < 0) |
| |
return -1; |
| |
continue; |
| |
#else |
| |
rprintf(FERROR, "GSSAPI is not supported\n"); |
| |
return -1; |
| |
#endif |
| |
} |
| |
|
| if (strcmp(line,"@RSYNCD: OK") == 0) |
if (strcmp(line,"@RSYNCD: OK") == 0) |
| break; |
break; |
| |
|
|
Line 348 int start_inband_exchange(int f_in, int f_out, const c
|
Line 394 int start_inband_exchange(int f_in, int f_out, const c
|
| return 0; |
return 0; |
| } |
} |
| |
|
| static char *finish_pre_exec(pid_t pid, int write_fd, int read_fd, char *request, | #ifdef HAVE_PUTENV |
| char **early_argv, char **argv) | static int read_arg_from_pipe(int fd, char *buf, int limit) |
| { |
{ |
| char buf[BIGPATHBUFLEN], *bp; | char *bp = buf, *eob = buf + limit - 1; |
| int j = 0, status = -1, msglen = sizeof buf - 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 |
| |
|
| |
static void set_env_str(const char *var, const char *str) |
| |
{ |
| |
#ifdef HAVE_PUTENV |
| |
char *mem; |
| |
if (asprintf(&mem, "%s=%s", var, str) < 0) |
| |
out_of_memory("set_env_str"); |
| |
putenv(mem); |
| |
#endif |
| |
} |
| |
|
| |
#ifdef HAVE_PUTENV |
| |
void set_env_num(const char *var, long num) |
| |
{ |
| |
char *mem; |
| |
if (asprintf(&mem, "%s=%ld", var, num) < 0) |
| |
out_of_memory("set_env_num"); |
| |
putenv(mem); |
| |
} |
| |
#endif |
| |
|
| |
/* Used for "early exec", "pre-xfer exec", and the "name converter" script. */ |
| |
static pid_t start_pre_exec(const char *cmd, int *arg_fd_ptr, int *error_fd_ptr) |
| |
{ |
| |
int arg_fds[2], error_fds[2], arg_fd; |
| |
pid_t pid; |
| |
|
| |
if ((error_fd_ptr && pipe(error_fds) < 0) || pipe(arg_fds) < 0 || (pid = fork()) < 0) |
| |
return (pid_t)-1; |
| |
|
| |
if (pid == 0) { |
| |
char buf[BIGPATHBUFLEN]; |
| |
int j, len, status; |
| |
|
| |
if (error_fd_ptr) { |
| |
close(error_fds[0]); |
| |
set_blocking(error_fds[1]); |
| |
} |
| |
|
| |
close(arg_fds[1]); |
| |
arg_fd = arg_fds[0]; |
| |
set_blocking(arg_fd); |
| |
|
| |
len = read_arg_from_pipe(arg_fd, buf, BIGPATHBUFLEN); |
| |
if (len <= 0) |
| |
_exit(1); |
| |
set_env_str("RSYNC_REQUEST", buf); |
| |
|
| |
for (j = 0; ; j++) { |
| |
char *p; |
| |
len = read_arg_from_pipe(arg_fd, buf, BIGPATHBUFLEN); |
| |
if (len <= 0) { |
| |
if (!len) |
| |
break; |
| |
_exit(1); |
| |
} |
| |
if (asprintf(&p, "RSYNC_ARG%d=%s", j, buf) >= 0) |
| |
putenv(p); |
| |
} |
| |
|
| |
dup2(arg_fd, STDIN_FILENO); |
| |
close(arg_fd); |
| |
|
| |
if (error_fd_ptr) { |
| |
dup2(error_fds[1], STDOUT_FILENO); |
| |
close(error_fds[1]); |
| |
} |
| |
|
| |
status = shell_exec(cmd); |
| |
|
| |
if (!WIFEXITED(status)) |
| |
_exit(1); |
| |
_exit(WEXITSTATUS(status)); |
| |
} |
| |
|
| |
if (error_fd_ptr) { |
| |
close(error_fds[1]); |
| |
*error_fd_ptr = error_fds[0]; |
| |
set_blocking(error_fds[0]); |
| |
} |
| |
|
| |
close(arg_fds[0]); |
| |
arg_fd = *arg_fd_ptr = arg_fds[1]; |
| |
set_blocking(arg_fd); |
| |
|
| |
return pid; |
| |
} |
| |
|
| |
static void write_pre_exec_args(int write_fd, char *request, char **early_argv, char **argv, int exec_type) |
| |
{ |
| |
int j = 0; |
| |
|
| if (!request) |
if (!request) |
| request = "(NONE)"; |
request = "(NONE)"; |
| |
|
|
Line 363 static char *finish_pre_exec(pid_t pid, int write_fd,
|
Line 517 static char *finish_pre_exec(pid_t pid, int write_fd,
|
| write_buf(write_fd, *early_argv, strlen(*early_argv)+1); |
write_buf(write_fd, *early_argv, strlen(*early_argv)+1); |
| j = 1; /* Skip arg0 name in argv. */ |
j = 1; /* Skip arg0 name in argv. */ |
| } |
} |
| for ( ; argv[j]; j++) | if (argv) { |
| write_buf(write_fd, argv[j], strlen(argv[j])+1); | for ( ; argv[j]; j++) |
| | write_buf(write_fd, argv[j], strlen(argv[j])+1); |
| | } |
| write_byte(write_fd, 0); |
write_byte(write_fd, 0); |
| |
|
| close(write_fd); | if (exec_type == 1 && early_input_len) |
| | write_buf(write_fd, early_input, early_input_len); |
| |
|
| /* Read the stdout from the pre-xfer exec program. This it is only | if (exec_type != 2) /* the name converter needs this left open */ |
| * displayed to the user if the script also returns an error status. */ | close(write_fd); |
| for (bp = buf; msglen > 0; msglen -= j) { | } |
| if ((j = read(read_fd, bp, msglen)) <= 0) { | |
| if (j == 0) | static char *finish_pre_exec(const char *desc, pid_t pid, int read_fd) |
| break; | { |
| if (errno == EINTR) | char buf[BIGPATHBUFLEN], *bp, *cr; |
| continue; | int j, status = -1, msglen = sizeof buf - 1; |
| break; /* Just ignore the read error for now... */ | |
| | if (read_fd >= 0) { |
| | /* Read the stdout from the program. This it is only displayed |
| | * to the user if the script also returns an error status. */ |
| | for (bp = buf, cr = buf; msglen > 0; msglen -= j) { |
| | if ((j = read(read_fd, bp, msglen)) <= 0) { |
| | if (j == 0) |
| | break; |
| | if (errno == EINTR) |
| | continue; |
| | break; /* Just ignore the read error for now... */ |
| | } |
| | bp[j] = '\0'; |
| | while (1) { |
| | if ((cr = strchr(cr, '\r')) == NULL) { |
| | cr = bp + j; |
| | break; |
| | } |
| | if (!cr[1]) |
| | break; /* wait for more data before we decide what to do */ |
| | if (cr[1] == '\n') { |
| | memmove(cr, cr+1, j - (cr - bp)); |
| | j--; |
| | } else |
| | cr++; |
| | } |
| | bp += j; |
| } |
} |
| bp += j; | *bp = '\0'; |
| if (j > 1 && bp[-1] == '\n' && bp[-2] == '\r') { | |
| bp--; | |
| j--; | |
| bp[-1] = '\n'; | |
| } | |
| } | |
| *bp = '\0'; | |
| |
|
| close(read_fd); | close(read_fd); |
| | } else |
| | *buf = '\0'; |
| |
|
| if (wait_process(pid, &status, 0) < 0 |
if (wait_process(pid, &status, 0) < 0 |
| || !WIFEXITED(status) || WEXITSTATUS(status) != 0) { |
|| !WIFEXITED(status) || WEXITSTATUS(status) != 0) { |
| char *e; |
char *e; |
| if (asprintf(&e, "pre-xfer exec returned failure (%d)%s%s%s\n%s", | if (asprintf(&e, "%s returned failure (%d)%s%s%s\n%s", |
| status, status < 0 ? ": " : "", | desc, status, status < 0 ? ": " : "", |
| status < 0 ? strerror(errno) : "", |
status < 0 ? strerror(errno) : "", |
| *buf ? ":" : "", buf) < 0) |
*buf ? ":" : "", buf) < 0) |
| return "out_of_memory in finish_pre_exec\n"; |
return "out_of_memory in finish_pre_exec\n"; |
|
Line 403 static char *finish_pre_exec(pid_t pid, int write_fd,
|
Line 581 static char *finish_pre_exec(pid_t pid, int write_fd,
|
| return NULL; |
return NULL; |
| } |
} |
| |
|
| #ifdef 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 |
|
| |
|
| static int path_failure(int f_out, const char *dir, BOOL was_chdir) |
static int path_failure(int f_out, const char *dir, BOOL was_chdir) |
| { |
{ |
| if (was_chdir) |
if (was_chdir) |
| rsyserr(FLOG, errno, "chdir %s failed\n", dir); | rsyserr(FLOG, errno, "chdir %s failed", dir); |
| else |
else |
| rprintf(FLOG, "normalize_path(%s) failed\n", dir); |
rprintf(FLOG, "normalize_path(%s) failed\n", dir); |
| io_printf(f_out, "@ERROR: chdir failed\n"); |
io_printf(f_out, "@ERROR: chdir failed\n"); |
|
Line 438 static int path_failure(int f_out, const char *dir, BO
|
Line 593 static int path_failure(int f_out, const char *dir, BO
|
| |
|
| static int add_a_group(int f_out, const char *gname) |
static int add_a_group(int f_out, const char *gname) |
| { |
{ |
| gid_t gid; | gid_t gid, *gid_p; |
| if (!group_to_gid(gname, &gid, True)) { |
if (!group_to_gid(gname, &gid, True)) { |
| rprintf(FLOG, "Invalid gid %s\n", gname); |
rprintf(FLOG, "Invalid gid %s\n", gname); |
| io_printf(f_out, "@ERROR: invalid gid %s\n", gname); |
io_printf(f_out, "@ERROR: invalid gid %s\n", gname); |
| return -1; |
return -1; |
| } |
} |
| if (gid_count == MAX_GID_LIST) { | gid_p = EXPAND_ITEM_LIST(&gid_list, gid_t, -32); |
| rprintf(FLOG, "Too many groups specified via gid parameter.\n"); | *gid_p = gid; |
| io_printf(f_out, "@ERROR: too many groups\n"); | |
| return -1; | |
| } | |
| gid_list[gid_count++] = gid; | |
| return 0; |
return 0; |
| } |
} |
| |
|
|
Line 457 static int add_a_group(int f_out, const char *gname)
|
Line 608 static int add_a_group(int f_out, const char *gname)
|
| static int want_all_groups(int f_out, uid_t uid) |
static int want_all_groups(int f_out, uid_t uid) |
| { |
{ |
| const char *err; |
const char *err; |
| gid_count = MAX_GID_LIST; | if ((err = getallgroups(uid, &gid_list)) != NULL) { |
| if ((err = getallgroups(uid, gid_list, &gid_count)) != NULL) { | |
| rsyserr(FLOG, errno, "%s", err); |
rsyserr(FLOG, errno, "%s", err); |
| io_printf(f_out, "@ERROR: %s\n", err); |
io_printf(f_out, "@ERROR: %s\n", err); |
| return -1; |
return -1; |
|
Line 469 static int want_all_groups(int f_out, uid_t uid)
|
Line 619 static int want_all_groups(int f_out, uid_t uid)
|
| static struct passwd *want_all_groups(int f_out, uid_t uid) |
static struct passwd *want_all_groups(int f_out, uid_t uid) |
| { |
{ |
| struct passwd *pw; |
struct passwd *pw; |
| |
gid_t *gid_p; |
| if ((pw = getpwuid(uid)) == NULL) { |
if ((pw = getpwuid(uid)) == NULL) { |
| rsyserr(FLOG, errno, "getpwuid failed"); |
rsyserr(FLOG, errno, "getpwuid failed"); |
| io_printf(f_out, "@ERROR: getpwuid failed\n"); |
io_printf(f_out, "@ERROR: getpwuid failed\n"); |
| return NULL; |
return NULL; |
| } |
} |
| /* Start with the default group and initgroups() will add the reset. */ | /* Start with the default group and initgroups() will add the rest. */ |
| gid_count = 1; | gid_p = EXPAND_ITEM_LIST(&gid_list, gid_t, -32); |
| gid_list[0] = pw->pw_gid; | *gid_p = pw->pw_gid; |
| return pw; |
return pw; |
| } |
} |
| #endif |
#endif |
| |
|
| static void set_env_str(const char *var, const char *str) |
|
| { |
|
| #ifdef HAVE_PUTENV |
|
| char *mem; |
|
| if (asprintf(&mem, "%s=%s", var, str) < 0) |
|
| out_of_memory("set_env_str"); |
|
| putenv(mem); |
|
| #endif |
|
| } |
|
| |
|
| #ifdef HAVE_PUTENV |
|
| static void set_env_num(const char *var, long num) |
|
| { |
|
| char *mem; |
|
| if (asprintf(&mem, "%s=%ld", var, num) < 0) |
|
| out_of_memory("set_env_num"); |
|
| putenv(mem); |
|
| } |
|
| #endif |
|
| |
|
| static int rsync_module(int f_in, int f_out, int i, const char *addr, const char *host) |
static int rsync_module(int f_in, int f_out, int i, const char *addr, const char *host) |
| { |
{ |
| int argc; |
int argc; |
|
Line 531 static int rsync_module(int f_in, int f_out, int i, co
|
Line 662 static int rsync_module(int f_in, int f_out, int i, co
|
| /* If reverse lookup is disabled globally but enabled for this module, |
/* If reverse lookup is disabled globally but enabled for this module, |
| * we need to do it now before the access check. */ |
* we need to do it now before the access check. */ |
| if (host == undetermined_hostname && lp_reverse_lookup(i)) |
if (host == undetermined_hostname && lp_reverse_lookup(i)) |
| host = client_name(f_in); | host = client_name(client_addr(f_in)); |
| set_env_str("RSYNC_HOST_NAME", host); |
set_env_str("RSYNC_HOST_NAME", host); |
| set_env_str("RSYNC_HOST_ADDR", addr); |
set_env_str("RSYNC_HOST_ADDR", addr); |
| |
|
|
Line 548 static int rsync_module(int f_in, int f_out, int i, co
|
Line 679 static int rsync_module(int f_in, int f_out, int i, co
|
| return -1; |
return -1; |
| } |
} |
| |
|
| if (am_daemon && am_server) { | if (*lp_link_by_hash_dir(i)) |
| | link_by_hash_dir = lp_link_by_hash_dir(i); |
| | |
| | if (am_daemon > 0) { |
| rprintf(FLOG, "rsync allowed access on module %s from %s (%s)\n", |
rprintf(FLOG, "rsync allowed access on module %s from %s (%s)\n", |
| name, host, addr); |
name, host, addr); |
| } |
} |
|
Line 568 static int rsync_module(int f_in, int f_out, int i, co
|
Line 702 static int rsync_module(int f_in, int f_out, int i, co
|
| } |
} |
| |
|
| read_only = lp_read_only(i); /* may also be overridden by auth_server() */ |
read_only = lp_read_only(i); /* may also be overridden by auth_server() */ |
| auth_user = auth_server(f_in, f_out, i, host, addr, "@RSYNCD: AUTHREQD "); | #ifdef GSSAPI_OPTION |
| | if (lp_use_gssapi(i)) |
| | auth_user = auth_gss_server(f_in, f_out, i, host, addr, "@RSYNCD: GSS"); |
| | else |
| | #endif |
| | auth_user = auth_server(f_in, f_out, i, host, addr, "@RSYNCD: AUTHREQD "); |
| |
|
| if (!auth_user) { |
if (!auth_user) { |
| io_printf(f_out, "@ERROR: auth failed on module %s\n", name); |
io_printf(f_out, "@ERROR: auth failed on module %s\n", name); |
|
Line 578 static int rsync_module(int f_in, int f_out, int i, co
|
Line 717 static int rsync_module(int f_in, int f_out, int i, co
|
| |
|
| module_id = i; |
module_id = i; |
| |
|
| if (lp_transfer_logging(i) && !logfile_format) | if (lp_transfer_logging(module_id) && !logfile_format) |
| logfile_format = lp_log_format(i); | logfile_format = lp_log_format(module_id); |
| if (log_format_has(logfile_format, 'i')) |
if (log_format_has(logfile_format, 'i')) |
| logfile_format_has_i = 1; |
logfile_format_has_i = 1; |
| if (logfile_format_has_i || log_format_has(logfile_format, 'o')) |
if (logfile_format_has_i || log_format_has(logfile_format, 'o')) |
| logfile_format_has_o_or_i = 1; |
logfile_format_has_o_or_i = 1; |
| |
|
| uid = MY_UID(); |
uid = MY_UID(); |
| am_root = (uid == 0); | am_root = (uid == ROOT_UID); |
| |
|
| p = *lp_uid(i) ? lp_uid(i) : am_root ? NOBODY_USER : NULL; | p = *lp_uid(module_id) ? lp_uid(module_id) : am_root ? NOBODY_USER : NULL; |
| if (p) { |
if (p) { |
| if (!user_to_uid(p, &uid, True)) { |
if (!user_to_uid(p, &uid, True)) { |
| rprintf(FLOG, "Invalid uid %s\n", p); |
rprintf(FLOG, "Invalid uid %s\n", p); |
|
Line 599 static int rsync_module(int f_in, int f_out, int i, co
|
Line 738 static int rsync_module(int f_in, int f_out, int i, co
|
| } else |
} else |
| set_uid = 0; |
set_uid = 0; |
| |
|
| p = *lp_gid(i) ? strtok(lp_gid(i), ", ") : NULL; | p = *lp_gid(module_id) ? conf_strtok(lp_gid(module_id)) : NULL; |
| if (p) { |
if (p) { |
| /* The "*" gid must be the first item in the list. */ |
/* The "*" gid must be the first item in the list. */ |
| if (strcmp(p, "*") == 0) { |
if (strcmp(p, "*") == 0) { |
|
Line 616 static int rsync_module(int f_in, int f_out, int i, co
|
Line 755 static int rsync_module(int f_in, int f_out, int i, co
|
| #endif |
#endif |
| } else if (add_a_group(f_out, p) < 0) |
} else if (add_a_group(f_out, p) < 0) |
| return -1; |
return -1; |
| while ((p = strtok(NULL, ", ")) != NULL) { | while ((p = conf_strtok(NULL)) != NULL) { |
| #if defined HAVE_INITGROUPS && !defined HAVE_GETGROUPLIST |
#if defined HAVE_INITGROUPS && !defined HAVE_GETGROUPLIST |
| if (pw) { |
if (pw) { |
| rprintf(FLOG, "This rsync cannot add groups after \"*\".\n"); |
rprintf(FLOG, "This rsync cannot add groups after \"*\".\n"); |
|
Line 632 static int rsync_module(int f_in, int f_out, int i, co
|
Line 771 static int rsync_module(int f_in, int f_out, int i, co
|
| return -1; |
return -1; |
| } |
} |
| |
|
| module_dir = lp_path(i); | module_dir = lp_path(module_id); |
| if (*module_dir == '\0') { |
if (*module_dir == '\0') { |
| rprintf(FLOG, "No path specified for module %s\n", name); |
rprintf(FLOG, "No path specified for module %s\n", name); |
| io_printf(f_out, "@ERROR: no path setting.\n"); |
io_printf(f_out, "@ERROR: no path setting.\n"); |
|
Line 669 static int rsync_module(int f_in, int f_out, int i, co
|
Line 808 static int rsync_module(int f_in, int f_out, int i, co
|
| } else |
} else |
| set_filter_dir(module_dir, module_dirlen); |
set_filter_dir(module_dir, module_dirlen); |
| |
|
| p = lp_filter(i); | p = lp_filter(module_id); |
| parse_filter_str(&daemon_filter_list, p, rule_template(FILTRULE_WORD_SPLIT), |
parse_filter_str(&daemon_filter_list, p, rule_template(FILTRULE_WORD_SPLIT), |
| XFLG_ABS_IF_SLASH | XFLG_DIR2WILD3); | XFLG_ABS_IF_SLASH | XFLG_DIR2WILD3); |
| |
|
| p = lp_include_from(i); | p = lp_include_from(module_id); |
| parse_filter_file(&daemon_filter_list, p, rule_template(FILTRULE_INCLUDE), |
parse_filter_file(&daemon_filter_list, p, rule_template(FILTRULE_INCLUDE), |
| XFLG_ABS_IF_SLASH | XFLG_DIR2WILD3 | XFLG_OLD_PREFIXES | XFLG_FATAL_ERRORS); | XFLG_ABS_IF_SLASH | XFLG_DIR2WILD3 | XFLG_OLD_PREFIXES | XFLG_FATAL_ERRORS); |
| |
|
| p = lp_include(i); | p = lp_include(module_id); |
| parse_filter_str(&daemon_filter_list, p, |
parse_filter_str(&daemon_filter_list, p, |
| rule_template(FILTRULE_INCLUDE | FILTRULE_WORD_SPLIT), | rule_template(FILTRULE_INCLUDE | FILTRULE_WORD_SPLIT), |
| XFLG_ABS_IF_SLASH | XFLG_DIR2WILD3 | XFLG_OLD_PREFIXES); | XFLG_ABS_IF_SLASH | XFLG_DIR2WILD3 | XFLG_OLD_PREFIXES); |
| |
|
| p = lp_exclude_from(i); | p = lp_exclude_from(module_id); |
| parse_filter_file(&daemon_filter_list, p, rule_template(0), |
parse_filter_file(&daemon_filter_list, p, rule_template(0), |
| XFLG_ABS_IF_SLASH | XFLG_DIR2WILD3 | XFLG_OLD_PREFIXES | XFLG_FATAL_ERRORS); | XFLG_ABS_IF_SLASH | XFLG_DIR2WILD3 | XFLG_OLD_PREFIXES | XFLG_FATAL_ERRORS); |
| |
|
| p = lp_exclude(i); | p = lp_exclude(module_id); |
| parse_filter_str(&daemon_filter_list, p, rule_template(FILTRULE_WORD_SPLIT), |
parse_filter_str(&daemon_filter_list, p, rule_template(FILTRULE_WORD_SPLIT), |
| XFLG_ABS_IF_SLASH | XFLG_DIR2WILD3 | XFLG_OLD_PREFIXES); | XFLG_ABS_IF_SLASH | XFLG_DIR2WILD3 | XFLG_OLD_PREFIXES); |
| |
|
| log_init(1); |
log_init(1); |
| |
|
| |
if (*lp_db_config(i)) { |
| |
db_read_config(FLOG, lp_db_config(i)); |
| |
db_lax = lp_db_lax(i); |
| |
} |
| |
|
| #ifdef HAVE_PUTENV |
#ifdef HAVE_PUTENV |
| if (*lp_prexfer_exec(i) || *lp_postxfer_exec(i)) { | if ((*lp_early_exec(module_id) || *lp_prexfer_exec(module_id) |
| int status; | || *lp_postxfer_exec(module_id) || *lp_name_converter(module_id)) |
| | && !getenv("RSYNC_NO_XFER_EXEC")) { |
| | set_env_num("RSYNC_PID", (long)getpid()); |
| |
|
| /* For post-xfer exec, fork a new process to run the rsync |
/* For post-xfer exec, fork a new process to run the rsync |
| * daemon while this process waits for the exit status and |
* daemon while this process waits for the exit status and |
| * runs the indicated command at that point. */ |
* runs the indicated command at that point. */ |
| if (*lp_postxfer_exec(i)) { | if (*lp_postxfer_exec(module_id)) { |
| pid_t pid = fork(); |
pid_t pid = fork(); |
| if (pid < 0) { |
if (pid < 0) { |
| rsyserr(FLOG, errno, "fork failed"); |
rsyserr(FLOG, errno, "fork failed"); |
|
Line 707 static int rsync_module(int f_in, int f_out, int i, co
|
Line 853 static int rsync_module(int f_in, int f_out, int i, co
|
| return -1; |
return -1; |
| } |
} |
| if (pid) { |
if (pid) { |
| |
int status; |
| close(f_in); |
close(f_in); |
| if (f_out != f_in) |
if (f_out != f_in) |
| close(f_out); |
close(f_out); |
| set_env_num("RSYNC_PID", (long)pid); |
|
| if (wait_process(pid, &status, 0) < 0) |
if (wait_process(pid, &status, 0) < 0) |
| status = -1; |
status = -1; |
| set_env_num("RSYNC_RAW_STATUS", status); |
set_env_num("RSYNC_RAW_STATUS", status); |
|
Line 719 static int rsync_module(int f_in, int f_out, int i, co
|
Line 865 static int rsync_module(int f_in, int f_out, int i, co
|
| else |
else |
| status = -1; |
status = -1; |
| set_env_num("RSYNC_EXIT_STATUS", status); |
set_env_num("RSYNC_EXIT_STATUS", status); |
| if (system(lp_postxfer_exec(i)) < 0) | if (shell_exec(lp_postxfer_exec(module_id)) < 0) |
| status = -1; |
status = -1; |
| _exit(status); |
_exit(status); |
| } |
} |
| } |
} |
| |
|
| |
/* For early exec, fork a child process to run the indicated |
| |
* command and wait for it to exit. */ |
| |
if (*lp_early_exec(module_id)) { |
| |
int arg_fd; |
| |
pid_t pid = start_pre_exec(lp_early_exec(module_id), &arg_fd, NULL); |
| |
if (pid == (pid_t)-1) { |
| |
rsyserr(FLOG, errno, "early exec preparation failed"); |
| |
io_printf(f_out, "@ERROR: early exec preparation failed\n"); |
| |
return -1; |
| |
} |
| |
write_pre_exec_args(arg_fd, NULL, NULL, NULL, 1); |
| |
if (finish_pre_exec("early exec", pid, -1) != NULL) { |
| |
rsyserr(FLOG, errno, "early exec failed"); |
| |
io_printf(f_out, "@ERROR: early exec failed\n"); |
| |
return -1; |
| |
} |
| |
} |
| |
|
| /* For pre-xfer exec, fork a child process to run the indicated |
/* For pre-xfer exec, fork a child process to run the indicated |
| * command, though it first waits for the parent process to |
* command, though it first waits for the parent process to |
| * send us the user's request via a pipe. */ |
* send us the user's request via a pipe. */ |
| if (*lp_prexfer_exec(i)) { | if (*lp_prexfer_exec(module_id)) { |
| int arg_fds[2], error_fds[2]; | pre_exec_pid = start_pre_exec(lp_prexfer_exec(module_id), &pre_exec_arg_fd, &pre_exec_error_fd); |
| set_env_num("RSYNC_PID", (long)getpid()); | if (pre_exec_pid == (pid_t)-1) { |
| if (pipe(arg_fds) < 0 || pipe(error_fds) < 0 || (pre_exec_pid = fork()) < 0) { | |
| rsyserr(FLOG, errno, "pre-xfer exec preparation failed"); |
rsyserr(FLOG, errno, "pre-xfer exec preparation failed"); |
| io_printf(f_out, "@ERROR: pre-xfer exec preparation failed\n"); |
io_printf(f_out, "@ERROR: pre-xfer exec preparation failed\n"); |
| return -1; |
return -1; |
| } |
} |
| if (pre_exec_pid == 0) { | } |
| char buf[BIGPATHBUFLEN]; | |
| int j, len; | if (*lp_name_converter(module_id)) { |
| close(arg_fds[1]); | namecvt_pid = start_pre_exec(lp_name_converter(module_id), &namecvt_fd_req, &namecvt_fd_ans); |
| close(error_fds[0]); | if (namecvt_pid == (pid_t)-1) { |
| pre_exec_arg_fd = arg_fds[0]; | rsyserr(FLOG, errno, "name-converter exec preparation failed"); |
| pre_exec_error_fd = error_fds[1]; | io_printf(f_out, "@ERROR: name-converter exec preparation failed\n"); |
| set_blocking(pre_exec_arg_fd); | return -1; |
| set_blocking(pre_exec_error_fd); | |
| len = read_arg_from_pipe(pre_exec_arg_fd, buf, BIGPATHBUFLEN); | |
| if (len <= 0) | |
| _exit(1); | |
| set_env_str("RSYNC_REQUEST", buf); | |
| for (j = 0; ; j++) { | |
| len = read_arg_from_pipe(pre_exec_arg_fd, buf, | |
| BIGPATHBUFLEN); | |
| if (len <= 0) { | |
| if (!len) | |
| break; | |
| _exit(1); | |
| } | |
| if (asprintf(&p, "RSYNC_ARG%d=%s", j, buf) >= 0) | |
| putenv(p); | |
| } | |
| close(pre_exec_arg_fd); | |
| close(STDIN_FILENO); | |
| dup2(pre_exec_error_fd, STDOUT_FILENO); | |
| close(pre_exec_error_fd); | |
| status = system(lp_prexfer_exec(i)); | |
| if (!WIFEXITED(status)) | |
| _exit(1); | |
| _exit(WEXITSTATUS(status)); | |
| } |
} |
| close(arg_fds[0]); |
|
| close(error_fds[1]); |
|
| pre_exec_arg_fd = arg_fds[1]; |
|
| pre_exec_error_fd = error_fds[0]; |
|
| set_blocking(pre_exec_arg_fd); |
|
| set_blocking(pre_exec_error_fd); |
|
| } |
} |
| } |
} |
| #endif |
#endif |
| |
|
| |
if (early_input) { |
| |
free(early_input); |
| |
early_input = NULL; |
| |
} |
| |
|
| if (use_chroot) { |
if (use_chroot) { |
| /* |
/* |
| * XXX: The 'use chroot' flag is a fairly reliable |
* XXX: The 'use chroot' flag is a fairly reliable |
|
Line 801 static int rsync_module(int f_in, int f_out, int i, co
|
Line 940 static int rsync_module(int f_in, int f_out, int i, co
|
| |
|
| if (!change_dir(module_chdir, CD_NORMAL)) |
if (!change_dir(module_chdir, CD_NORMAL)) |
| return path_failure(f_out, module_chdir, True); |
return path_failure(f_out, module_chdir, True); |
| if (module_dirlen || !use_chroot) | if (module_dirlen || (!use_chroot && !*lp_daemon_chroot())) |
| sanitize_paths = 1; |
sanitize_paths = 1; |
| |
|
| if ((munge_symlinks = lp_munge_symlinks(i)) < 0) | if ((munge_symlinks = lp_munge_symlinks(module_id)) < 0) |
| munge_symlinks = !use_chroot || module_dirlen; |
munge_symlinks = !use_chroot || module_dirlen; |
| if (munge_symlinks) { |
if (munge_symlinks) { |
| STRUCT_STAT st; |
STRUCT_STAT st; |
|
Line 818 static int rsync_module(int f_in, int f_out, int i, co
|
Line 957 static int rsync_module(int f_in, int f_out, int i, co
|
| } |
} |
| } |
} |
| |
|
| if (gid_count) { | if (gid_list.count) { |
| if (setgid(gid_list[0])) { | gid_t *gid_array = gid_list.items; |
| rsyserr(FLOG, errno, "setgid %ld failed", (long)gid_list[0]); | if (setgid(gid_array[0])) { |
| | rsyserr(FLOG, errno, "setgid %ld failed", (long)gid_array[0]); |
| io_printf(f_out, "@ERROR: setgid failed\n"); |
io_printf(f_out, "@ERROR: setgid failed\n"); |
| return -1; |
return -1; |
| } |
} |
| #ifdef HAVE_SETGROUPS |
#ifdef HAVE_SETGROUPS |
| /* Set the group(s) we want to be active. */ |
/* Set the group(s) we want to be active. */ |
| if (setgroups(gid_count, gid_list)) { | if (setgroups(gid_list.count, gid_array)) { |
| rsyserr(FLOG, errno, "setgroups failed"); |
rsyserr(FLOG, errno, "setgroups failed"); |
| io_printf(f_out, "@ERROR: setgroups failed\n"); |
io_printf(f_out, "@ERROR: setgroups failed\n"); |
| return -1; |
return -1; |
|
Line 840 static int rsync_module(int f_in, int f_out, int i, co
|
Line 980 static int rsync_module(int f_in, int f_out, int i, co
|
| return -1; |
return -1; |
| } |
} |
| #endif |
#endif |
| |
our_gid = MY_GID(); |
| } |
} |
| |
|
| if (set_uid) { |
if (set_uid) { |
|
Line 853 static int rsync_module(int f_in, int f_out, int i, co
|
Line 994 static int rsync_module(int f_in, int f_out, int i, co
|
| return -1; |
return -1; |
| } |
} |
| |
|
| am_root = (MY_UID() == 0); | our_uid = MY_UID(); |
| | am_root = (our_uid == ROOT_UID); |
| } |
} |
| |
|
| if (lp_temp_dir(i) && *lp_temp_dir(i)) { | if (lp_temp_dir(module_id) && *lp_temp_dir(module_id)) { |
| tmpdir = lp_temp_dir(i); | tmpdir = lp_temp_dir(module_id); |
| if (strlen(tmpdir) >= MAXPATHLEN - 10) { |
if (strlen(tmpdir) >= MAXPATHLEN - 10) { |
| rprintf(FLOG, |
rprintf(FLOG, |
| "the 'temp dir' value for %s is WAY too long -- ignoring.\n", |
"the 'temp dir' value for %s is WAY too long -- ignoring.\n", |
|
Line 884 static int rsync_module(int f_in, int f_out, int i, co
|
Line 1026 static int rsync_module(int f_in, int f_out, int i, co
|
| } else |
} else |
| orig_early_argv = NULL; |
orig_early_argv = NULL; |
| |
|
| |
/* The default is to use the user's setting unless the module sets True or False. */ |
| |
if (lp_open_noatime(module_id) >= 0) |
| |
open_noatime = lp_open_noatime(module_id); |
| |
|
| munge_symlinks = save_munge_symlinks; /* The client mustn't control this. */ |
munge_symlinks = save_munge_symlinks; /* The client mustn't control this. */ |
| |
|
| |
if (am_daemon > 0) |
| |
msgs2stderr = 0; /* A non-rsh-run daemon doesn't have stderr for msgs. */ |
| |
|
| if (pre_exec_pid) { |
if (pre_exec_pid) { |
| err_msg = finish_pre_exec(pre_exec_pid, pre_exec_arg_fd, pre_exec_error_fd, | write_pre_exec_args(pre_exec_arg_fd, request, orig_early_argv, orig_argv, 0); |
| request, orig_early_argv, orig_argv); | err_msg = finish_pre_exec("pre-xfer exec", pre_exec_pid, pre_exec_error_fd); |
| } |
} |
| |
|
| |
if (namecvt_pid) |
| |
write_pre_exec_args(namecvt_fd_req, request, orig_early_argv, orig_argv, 2); |
| |
|
| if (orig_early_argv) |
if (orig_early_argv) |
| free(orig_early_argv); |
free(orig_early_argv); |
| |
|
| am_server = 1; /* Don't let someone try to be tricky. */ |
am_server = 1; /* Don't let someone try to be tricky. */ |
| quiet = 0; |
quiet = 0; |
| |
db_config = NULL; |
| |
|
| if (lp_ignore_errors(module_id)) |
if (lp_ignore_errors(module_id)) |
| ignore_errors = 1; |
ignore_errors = 1; |
| if (write_batch < 0) |
if (write_batch < 0) |
| dry_run = 1; |
dry_run = 1; |
| |
|
| if (lp_fake_super(i)) { | if (lp_fake_super(module_id)) { |
| if (preserve_xattrs > 1) |
if (preserve_xattrs > 1) |
| preserve_xattrs = 1; |
preserve_xattrs = 1; |
| am_root = -1; |
am_root = -1; |
| } else if (am_root < 0) /* Treat --fake-super from client as --super. */ |
} else if (am_root < 0) /* Treat --fake-super from client as --super. */ |
| am_root = 2; |
am_root = 2; |
| |
|
| |
checksum_files = always_checksum ? lp_checksum_files(i) |
| |
: CSF_IGNORE_FILES; |
| |
|
| if (filesfrom_fd == 0) |
if (filesfrom_fd == 0) |
| filesfrom_fd = f_in; |
filesfrom_fd = f_in; |
| |
|
|
Line 926 static int rsync_module(int f_in, int f_out, int i, co
|
Line 1083 static int rsync_module(int f_in, int f_out, int i, co
|
| |
|
| #ifndef DEBUG |
#ifndef DEBUG |
| /* don't allow the logs to be flooded too fast */ |
/* don't allow the logs to be flooded too fast */ |
| limit_output_verbosity(lp_max_verbosity(i)); | limit_output_verbosity(lp_max_verbosity(module_id)); |
| #endif |
#endif |
| |
|
| if (protocol_version < 23 | if (protocol_version < 23 && (protocol_version == 22 || am_sender)) |
| && (protocol_version == 22 || am_sender)) | |
| io_start_multiplex_out(f_out); |
io_start_multiplex_out(f_out); |
| else if (!ret || err_msg) { |
else if (!ret || err_msg) { |
| /* We have to get I/O multiplexing started so that we can |
/* We have to get I/O multiplexing started so that we can |
|
Line 967 static int rsync_module(int f_in, int f_out, int i, co
|
Line 1123 static int rsync_module(int f_in, int f_out, int i, co
|
| } |
} |
| if (*err_msg) |
if (*err_msg) |
| rprintf(FERROR, "%s\n", err_msg); |
rprintf(FERROR, "%s\n", err_msg); |
| |
io_flush(MSG_FLUSH); |
| } else |
} else |
| option_error(); |
option_error(); |
| msleep(400); |
msleep(400); |
|
Line 987 static int rsync_module(int f_in, int f_out, int i, co
|
Line 1144 static int rsync_module(int f_in, int f_out, int i, co
|
| #endif |
#endif |
| |
|
| if (!numeric_ids |
if (!numeric_ids |
| && (use_chroot ? lp_numeric_ids(i) != False : lp_numeric_ids(i) == True)) | && (use_chroot ? lp_numeric_ids(module_id) != False && !*lp_name_converter(module_id) |
| | : lp_numeric_ids(module_id) == True)) |
| numeric_ids = -1; /* Set --numeric-ids w/o breaking protocol. */ |
numeric_ids = -1; /* Set --numeric-ids w/o breaking protocol. */ |
| |
|
| if (lp_timeout(i) && (!io_timeout || lp_timeout(i) < io_timeout)) | if (lp_timeout(module_id) && (!io_timeout || lp_timeout(module_id) < io_timeout)) |
| set_io_timeout(lp_timeout(i)); | set_io_timeout(lp_timeout(module_id)); |
| |
|
| /* If we have some incoming/outgoing chmod changes, append them to |
/* If we have some incoming/outgoing chmod changes, append them to |
| * any user-specified changes (making our changes have priority). |
* any user-specified changes (making our changes have priority). |
| * We also get a pointer to just our changes so that a receiver |
* We also get a pointer to just our changes so that a receiver |
| * process can use them separately if --perms wasn't specified. */ |
* process can use them separately if --perms wasn't specified. */ |
| if (am_sender) |
if (am_sender) |
| p = lp_outgoing_chmod(i); | p = lp_outgoing_chmod(module_id); |
| else |
else |
| p = lp_incoming_chmod(i); | p = lp_incoming_chmod(module_id); |
| if (*p && !(daemon_chmod_modes = parse_chmod(p, &chmod_modes))) { |
if (*p && !(daemon_chmod_modes = parse_chmod(p, &chmod_modes))) { |
| rprintf(FLOG, "Invalid \"%sing chmod\" directive: %s\n", |
rprintf(FLOG, "Invalid \"%sing chmod\" directive: %s\n", |
| am_sender ? "outgo" : "incom", p); |
am_sender ? "outgo" : "incom", p); |
|
Line 1011 static int rsync_module(int f_in, int f_out, int i, co
|
Line 1169 static int rsync_module(int f_in, int f_out, int i, co
|
| return 0; |
return 0; |
| } |
} |
| |
|
| |
BOOL namecvt_call(const char *cmd, const char **name_p, id_t *id_p) |
| |
{ |
| |
char buf[1024]; |
| |
int got, len; |
| |
|
| |
if (*name_p) |
| |
len = snprintf(buf, sizeof buf, "%s %s\n", cmd, *name_p); |
| |
else |
| |
len = snprintf(buf, sizeof buf, "%s %ld\n", cmd, (long)*id_p); |
| |
if (len >= (int)sizeof buf) { |
| |
rprintf(FERROR, "namecvt_call() request was too large.\n"); |
| |
exit_cleanup(RERR_UNSUPPORTED); |
| |
} |
| |
|
| |
while ((got = write(namecvt_fd_req, buf, len)) != len) { |
| |
if (got < 0 && errno == EINTR) |
| |
continue; |
| |
rprintf(FERROR, "Connection to name-converter failed.\n"); |
| |
exit_cleanup(RERR_SOCKETIO); |
| |
} |
| |
|
| |
if (!read_line_old(namecvt_fd_ans, buf, sizeof buf, 0)) |
| |
return False; |
| |
|
| |
if (*name_p) |
| |
*id_p = (id_t)atol(buf); |
| |
else |
| |
*name_p = strdup(buf); |
| |
|
| |
return True; |
| |
} |
| |
|
| /* send a list of available modules to the client. Don't list those |
/* send a list of available modules to the client. Don't list those |
| with "list = False". */ |
with "list = False". */ |
| static void send_listing(int fd) |
static void send_listing(int fd) |
|
Line 1030 static void send_listing(int fd)
|
Line 1220 static void send_listing(int fd)
|
| static int load_config(int globals_only) |
static int load_config(int globals_only) |
| { |
{ |
| if (!config_file) { |
if (!config_file) { |
| if (am_server && am_root <= 0) | if (am_daemon < 0 && am_root <= 0) |
| config_file = RSYNCD_USERCONF; |
config_file = RSYNCD_USERCONF; |
| else |
else |
| config_file = RSYNCD_SYSCONF; |
config_file = RSYNCD_SYSCONF; |
|
Line 1045 int start_daemon(int f_in, int f_out)
|
Line 1235 int start_daemon(int f_in, int f_out)
|
| { |
{ |
| char line[1024]; |
char line[1024]; |
| const char *addr, *host; |
const char *addr, *host; |
| |
char *p; |
| int i; |
int i; |
| |
|
| |
/* At this point, am_server is only set for a daemon started via rsh. |
| |
* Because am_server gets forced on soon, we'll set am_daemon to -1 as |
| |
* a flag that can be checked later on to distinguish a normal daemon |
| |
* from an rsh-run daemon. */ |
| |
if (am_server) |
| |
am_daemon = -1; |
| |
|
| io_set_sock_fds(f_in, f_out); |
io_set_sock_fds(f_in, f_out); |
| |
|
| /* We must load the config file before calling any function that |
/* We must load the config file before calling any function that |
|
Line 1056 int start_daemon(int f_in, int f_out)
|
Line 1254 int start_daemon(int f_in, int f_out)
|
| if (!load_config(0)) |
if (!load_config(0)) |
| exit_cleanup(RERR_SYNTAX); |
exit_cleanup(RERR_SYNTAX); |
| |
|
| |
if (lp_proxy_protocol() && !read_proxy_protocol_header(f_in)) |
| |
return -1; |
| |
|
| |
p = lp_daemon_chroot(); |
| |
if (*p) { |
| |
log_init(0); /* Make use we've initialized syslog before chrooting. */ |
| |
if (chroot(p) < 0 || chdir("/") < 0) { |
| |
rsyserr(FLOG, errno, "daemon chroot %s failed", p); |
| |
return -1; |
| |
} |
| |
} |
| |
p = lp_daemon_gid(); |
| |
if (*p) { |
| |
gid_t gid; |
| |
if (!group_to_gid(p, &gid, True)) { |
| |
rprintf(FLOG, "Invalid daemon gid: %s\n", p); |
| |
return -1; |
| |
} |
| |
if (setgid(gid) < 0) { |
| |
rsyserr(FLOG, errno, "Unable to set group to daemon gid %ld", (long)gid); |
| |
return -1; |
| |
} |
| |
our_gid = MY_GID(); |
| |
} |
| |
p = lp_daemon_uid(); |
| |
if (*p) { |
| |
uid_t uid; |
| |
if (!user_to_uid(p, &uid, True)) { |
| |
rprintf(FLOG, "Invalid daemon uid: %s\n", p); |
| |
return -1; |
| |
} |
| |
if (setuid(uid) < 0) { |
| |
rsyserr(FLOG, errno, "Unable to set user to daemon uid %ld", (long)uid); |
| |
return -1; |
| |
} |
| |
our_uid = MY_UID(); |
| |
am_root = (our_uid == ROOT_UID); |
| |
} |
| |
|
| addr = client_addr(f_in); |
addr = client_addr(f_in); |
| host = lp_reverse_lookup(-1) ? client_name(f_in) : undetermined_hostname; | host = lp_reverse_lookup(-1) ? client_name(addr) : undetermined_hostname; |
| rprintf(FLOG, "connect from %s (%s)\n", host, addr); |
rprintf(FLOG, "connect from %s (%s)\n", host, addr); |
| |
|
| if (!am_server) { | if (am_daemon > 0) { |
| set_socket_options(f_in, "SO_KEEPALIVE"); |
set_socket_options(f_in, "SO_KEEPALIVE"); |
| set_nonblocking(f_in); |
set_nonblocking(f_in); |
| } |
} |
|
Line 1072 int start_daemon(int f_in, int f_out)
|
Line 1309 int start_daemon(int f_in, int f_out)
|
| if (!read_line_old(f_in, line, sizeof line, 0)) |
if (!read_line_old(f_in, line, sizeof line, 0)) |
| return -1; |
return -1; |
| |
|
| |
if (strncmp(line, EARLY_INPUT_CMD, EARLY_INPUT_CMDLEN) == 0) { |
| |
early_input_len = strtol(line + EARLY_INPUT_CMDLEN, NULL, 10); |
| |
if (early_input_len <= 0 || early_input_len > BIGPATHBUFLEN) { |
| |
io_printf(f_out, "@ERROR: invalid early_input length\n"); |
| |
return -1; |
| |
} |
| |
early_input = new_array(char, early_input_len); |
| |
read_buf(f_in, early_input, early_input_len); |
| |
|
| |
if (!read_line_old(f_in, line, sizeof line, 0)) |
| |
return -1; |
| |
} |
| |
|
| if (!*line || strcmp(line, "#list") == 0) { |
if (!*line || strcmp(line, "#list") == 0) { |
| rprintf(FLOG, "module-list request from %s (%s)\n", |
rprintf(FLOG, "module-list request from %s (%s)\n", |
| host, addr); |
host, addr); |
|
Line 1103 int start_daemon(int f_in, int f_out)
|
Line 1353 int start_daemon(int f_in, int f_out)
|
| static void create_pid_file(void) |
static void create_pid_file(void) |
| { |
{ |
| char *pid_file = lp_pid_file(); |
char *pid_file = lp_pid_file(); |
| char pidbuf[16]; | char pidbuf[32]; |
| pid_t pid = getpid(); | STRUCT_STAT st1, st2; |
| int fd, len; | char *fail = NULL; |
| |
|
| if (!pid_file || !*pid_file) |
if (!pid_file || !*pid_file) |
| return; |
return; |
| |
|
| cleanup_set_pid(pid); | #ifdef O_NOFOLLOW |
| if ((fd = do_open(pid_file, O_WRONLY|O_CREAT|O_EXCL, 0666)) == -1) { | #define SAFE_OPEN_FLAGS (O_CREAT|O_NOFOLLOW) |
| failure: | #else |
| cleanup_set_pid(0); | #define SAFE_OPEN_FLAGS (O_CREAT) |
| fprintf(stderr, "failed to create pid file %s: %s\n", pid_file, strerror(errno)); | #endif |
| rsyserr(FLOG, errno, "failed to create pid file %s", pid_file); | |
| | /* These tests make sure that a temp-style lock dir is handled safely. */ |
| | st1.st_mode = 0; |
| | if (do_lstat(pid_file, &st1) == 0 && !S_ISREG(st1.st_mode) && unlink(pid_file) < 0) |
| | fail = "unlink"; |
| | else if ((pid_file_fd = do_open(pid_file, O_RDWR|SAFE_OPEN_FLAGS, 0664)) < 0) |
| | fail = S_ISREG(st1.st_mode) ? "open" : "create"; |
| | else if (!lock_range(pid_file_fd, 0, 4)) |
| | fail = "lock"; |
| | else if (do_fstat(pid_file_fd, &st1) < 0) |
| | fail = "fstat opened"; |
| | else if (st1.st_size > (int)sizeof pidbuf) |
| | fail = "find small"; |
| | else if (do_lstat(pid_file, &st2) < 0) |
| | fail = "lstat"; |
| | else if (!S_ISREG(st1.st_mode)) |
| | fail = "avoid file overwrite race for"; |
| | else if (st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino) |
| | fail = "verify stat info for"; |
| | #ifdef HAVE_FTRUNCATE |
| | else if (do_ftruncate(pid_file_fd, 0) < 0) |
| | fail = "truncate"; |
| | #endif |
| | else { |
| | pid_t pid = getpid(); |
| | int len = snprintf(pidbuf, sizeof pidbuf, "%d\n", (int)pid); |
| | #ifndef HAVE_FTRUNCATE |
| | /* What can we do with a too-long file and no truncate? I guess we'll add extra newlines. */ |
| | while (len < st1.st_size) /* We already verified that st_size chars fits in the buffer. */ |
| | pidbuf[len++] = '\n'; |
| | /* We don't need the buffer to end in a '\0' (and we may not have room to add it). */ |
| | #endif |
| | if (write(pid_file_fd, pidbuf, len) != len) |
| | fail = "write"; |
| | cleanup_set_pid(pid); /* Mark the file for removal on exit, even if the write failed. */ |
| | } |
| | |
| | if (fail) { |
| | char msg[1024]; |
| | snprintf(msg, sizeof msg, "failed to %s pid file %s: %s\n", |
| | fail, pid_file, strerror(errno)); |
| | fputs(msg, stderr); |
| | rprintf(FLOG, "%s", msg); |
| exit_cleanup(RERR_FILEIO); |
exit_cleanup(RERR_FILEIO); |
| } |
} |
| snprintf(pidbuf, sizeof pidbuf, "%d\n", (int)pid); | |
| len = strlen(pidbuf); | /* The file is left open so that the lock remains valid. It is closed in our forked child procs. */ |
| if (write(fd, pidbuf, len) != len) | |
| goto failure; | |
| close(fd); | |
| } |
} |
| |
|
| /* Become a daemon, discarding the controlling terminal. */ |
/* Become a daemon, discarding the controlling terminal. */ |
|
Line 1194 int daemon_main(void)
|
Line 1483 int daemon_main(void)
|
| log_init(0); |
log_init(0); |
| |
|
| rprintf(FLOG, "rsyncd version %s starting, listening on port %d\n", |
rprintf(FLOG, "rsyncd version %s starting, listening on port %d\n", |
| RSYNC_VERSION, rsync_port); | rsync_version(), rsync_port); |
| /* TODO: If listening on a particular address, then show that |
/* TODO: If listening on a particular address, then show that |
| * address too. In fact, why not just do getnameinfo on the |
* address too. In fact, why not just do getnameinfo on the |
| * local address??? */ |
* local address??? */ |
| |
|
| |
#ifdef HAVE_LIBSLP |
| |
if (lp_use_slp() && register_services()) { |
| |
rprintf(FINFO, |
| |
"Couldn't register with service discovery protocol, continuing anyway\n"); |
| |
} |
| |
#endif |
| |
|
| start_accept_loop(rsync_port, start_daemon); |
start_accept_loop(rsync_port, start_daemon); |
| return -1; |
return -1; |