diff --git a/lib/gprocess.h b/lib/gprocess.h index cda35b0..5c449f7 100644 --- a/lib/gprocess.h +++ b/lib/gprocess.h @@ -28,9 +28,14 @@ #include "syslog-ng.h" #include +#include #if ENABLE_LINUX_CAPS # include +# +# ifndef CAP_SYSLOG +# define CAP_SYSLOG 34 +# endif #endif typedef enum @@ -78,5 +83,8 @@ void g_process_finish(void); void g_process_add_option_group(GOptionContext *ctx); +extern int kernel_version; +extern void get_kernel_version(void); +#define LINUX_VERSION(x,y,z) (0x10000*(x) + 0x100*(y) + z) #endif diff --git a/modules/affile/affile.c b/modules/affile/affile.c index e145324..886fa72 100644 --- a/modules/affile/affile.c +++ b/modules/affile/affile.c @@ -59,7 +59,12 @@ affile_open_file(gchar *name, gint flags, if (privileged) { g_process_cap_modify(CAP_DAC_READ_SEARCH, TRUE); - g_process_cap_modify(CAP_SYS_ADMIN, TRUE); + if (!kernel_version) + get_kernel_version(); + if (kernel_version < LINUX_VERSION(2, 6, 38)) + g_process_cap_modify(CAP_SYS_ADMIN, TRUE); + else + g_process_cap_modify(CAP_SYSLOG, TRUE); } else { diff --git a/syslog-ng/main.c b/syslog-ng/main.c index 9880c1f..ee5031b 100644 --- a/syslog-ng/main.c +++ b/syslog-ng/main.c @@ -67,6 +67,7 @@ static gboolean syntax_only = FALSE; static gboolean display_version = FALSE; static gchar *ctlfilename = PATH_CONTROL_SOCKET; static gchar *preprocess_into = NULL; +int kernel_version; static volatile sig_atomic_t sig_hup_received = FALSE; static volatile sig_atomic_t sig_term_received = FALSE; @@ -363,6 +364,20 @@ version(void) ON_OFF_STR(ENABLE_PACCT_MODULE)); } +void +get_kernel_version(void) { + static struct utsname uts; + int x = 0, y = 0, z = 0; + + if (uname(&uts) == -1) { + fprintf(stderr, "Unable to retrieve kernel version.\n"); + exit(1); + } + + sscanf(uts.release, "%d.%d.%d", &x, &y, &z); + kernel_version = LINUX_VERSION(x, y, z); +} + int main(int argc, char *argv[]) { @@ -379,9 +394,20 @@ main(int argc, char *argv[]) * indicate readability. Enabling/disabling cap_sys_admin on every poll * invocation seems to be too expensive. So I enable it for now. */ - g_process_set_caps("cap_net_bind_service,cap_net_broadcast,cap_net_raw," + if (!kernel_version) + get_kernel_version(); + if (kernel_version < LINUX_VERSION(2, 6, 34)) + g_process_set_caps("cap_net_bind_service,cap_net_broadcast,cap_net_raw," "cap_dac_read_search,cap_dac_override,cap_chown,cap_fowner=p " "cap_sys_admin=ep"); + else if (kernel_version < LINUX_VERSION(2, 6, 38)) + g_process_set_caps("cap_net_bind_service,cap_net_broadcast,cap_net_raw," + "cap_dac_read_search,cap_dac_override,cap_chown,cap_fowner," + "cap_sys_admin=p"); + else + g_process_set_caps("cap_net_bind_service,cap_net_broadcast,cap_net_raw," + "cap_dac_read_search,cap_dac_override,cap_chown,cap_fowner," + "cap_syslog=p"); ctx = g_option_context_new("syslog-ng"); g_process_add_option_group(ctx); msg_add_option_group(ctx);