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; |