I was wondering if it might be possible for an rsync developer to look over the attached patch (tested on Linux 2.4.24 against the rsync-2.6.0 release), and offer suggestions on how I could improve it.
Basically I want to use Linux finer grained capabilities to retain only CAP_SYS_CHROOT & CAP_DAC_READ_SEARCH when rsync drops root privs. That way I can take whole system backups as a (mostly) unprivileged user. Probably it should be some kind of config file option or something rather than a simple compile-time option. Also it would be nice to drop root much earlier if possible, but where? Any suggestions are much appreciated! BTW, editing rsync source was not my first choice on how to tackle this. I would much rather use a small separate wrapper program to set the capabilities and then exec rsync, but alas capabilities cannot be passed across an exec. And it doesn't look like that's going to change anytime soon either: http://www.ussg.iu.edu/hypermail/linux/kernel/0310.2/index.html#1119 -- Michael Glasgow <[EMAIL PROTECTED]>
diff -urN rsync-2.6.0.orig/clientserver.c rsync-2.6.0/clientserver.c --- rsync-2.6.0.orig/clientserver.c 2003-09-10 23:00:19.000000000 -0500 +++ rsync-2.6.0/clientserver.c 2004-01-26 11:27:53.000000000 -0600 @@ -25,6 +25,18 @@ * rsyncd. **/ +#ifdef HAVE_LINUX_CAPS +#ifdef _POSIX_SOURCE +#undef _POSIX_SOURCE +#include <sys/prctl.h> +#include <sys/capability.h> +#define _POSIX_SOURCE +#else +#include <sys/prctl.h> +#include <sys/capability.h> +#endif +#endif + #include "rsync.h" extern int module_id; @@ -217,6 +229,10 @@ int start_glob=0; int ret; char *request=NULL; +#ifdef HAVE_LINUX_CAPS + cap_t cp; + cap_value_t newcaps[2] = { CAP_SYS_CHROOT, CAP_DAC_READ_SEARCH }; +#endif extern int am_sender; extern int am_server; extern int am_daemon; @@ -373,12 +389,46 @@ } #endif +#ifdef HAVE_LINUX_CAPS + if (setreuid(uid, 0)) { + rsyserr(FERROR, errno, "setreuid(%d,0) failed", (int) uid); + io_printf(f_out, "@ERROR: setreuid failed\n"); + return -1; + } + if( prctl(PR_SET_KEEPCAPS, 1) < 0 ) { + rsyserr(FERROR, errno, "prctl failed"); + io_printf(f_out, "@ERROR: prctl failed\n"); + return -1; + } + if( (cp = cap_init()) == NULL ) { + rsyserr(FERROR, errno, "cap_init failed"); + io_printf(f_out, "@ERROR: cap_init failed\n"); + return -1; + } + if( cap_set_flag(cp, CAP_PERMITTED, 2, newcaps, CAP_SET) < 0 || + cap_set_flag(cp, CAP_INHERITABLE, 2, newcaps, CAP_SET) < 0 ) { + rsyserr(FERROR, errno, "cap_set_flag failed"); + io_printf(f_out, "@ERROR: cap_set_flag failed\n"); + return -1; + } + if( cap_set_proc(cp) < 0 ) { + rsyserr(FERROR, errno, "cap_set_proc failed"); + io_printf(f_out, "@ERROR: cap_set_proc failed\n"); + return -1; + } +#endif + if (setuid(uid)) { rsyserr(FERROR, errno, "setuid %d failed", (int) uid); io_printf(f_out, "@ERROR: setuid failed\n"); return -1; } +#ifdef HAVE_LINUX_CAPS + cap_set_flag(cp, CAP_EFFECTIVE, 2, newcaps, CAP_SET); + cap_set_proc(cp); +#endif + am_root = (getuid() == 0); }
-- To unsubscribe or change options: http://lists.samba.org/mailman/listinfo/rsync Before posting, read: http://www.catb.org/~esr/faqs/smart-questions.html