----- Original Message ----- > Author: amc > Date: Mon Apr 25 19:29:02 2011 > New Revision: 1096571 > > URL: http://svn.apache.org/viewvc?rev=1096571&view=rev > Log: > TS-748 > > Added: > trafficserver/traffic/trunk/lib/ts/ink_cap.cc > trafficserver/traffic/trunk/lib/ts/ink_cap.h > Modified: > trafficserver/traffic/trunk/lib/ts/Makefile.am > trafficserver/traffic/trunk/proxy/Main.cc > trafficserver/traffic/trunk/proxy/http/HttpSM.cc > trafficserver/traffic/trunk/proxy/http/HttpTransact.cc > > Modified: trafficserver/traffic/trunk/lib/ts/Makefile.am > URL: > http://svn.apache.org/viewvc/trafficserver/traffic/trunk/lib/ts/Makefile.am?rev=1096571&r1=1096570&r2=1096571&view=diff > ============================================================================== > --- trafficserver/traffic/trunk/lib/ts/Makefile.am (original) > +++ trafficserver/traffic/trunk/lib/ts/Makefile.am Mon Apr 25 > 19:29:02 2011 > @@ -23,7 +23,7 @@ TESTS = $(check_PROGRAMS) > lib_LTLIBRARIES = libtsutil.la > > libtsutil_la_LDFLAGS = -no-undefined -version-info > @TS_LIBTOOL_VERSION@ > -libtsutil_la_LIBADD = @LIBOBJS@ @LIBPCRE@ @LIBSSL@ @LIBTCL@ > @LIBRESOLV@ @LIBRT@ @LIBICONV@ @LIBSOCKET@ @LIBNSL@ -lc > +libtsutil_la_LIBADD = @LIBOBJS@ @LIBPCRE@ @LIBSSL@ @LIBTCL@ > @LIBRESOLV@ @LIBRT@ @LIBICONV@ @LIBSOCKET@ @LIBNSL@ @LIBCAP@ -lc > > libtsutil_la_SOURCES = \ > Allocator.cc \ > @@ -53,6 +53,7 @@ libtsutil_la_SOURCES = \ > ink_base64.cc \ > ink_base64.h \ > ink_bool.h \ > + ink_cap.cc ink_cap.h \ > ink_code.cc \ > ink_code.h \ > ink_defs.cc \ > > Added: trafficserver/traffic/trunk/lib/ts/ink_cap.cc > URL: > http://svn.apache.org/viewvc/trafficserver/traffic/trunk/lib/ts/ink_cap.cc?rev=1096571&view=auto > ============================================================================== > --- trafficserver/traffic/trunk/lib/ts/ink_cap.cc (added) > +++ trafficserver/traffic/trunk/lib/ts/ink_cap.cc Mon Apr 25 19:29:02 > 2011 > @@ -0,0 +1,61 @@ > +# include "ink_config.h" > +# include "Diags.h" > +# include "ink_cap.h" > + > +# if TS_USE_POSIX_CAP > +# include <sys/capability.h> > +# include <sys/prctl.h> > +# endif > + > +void > +DebugCapabilities(char const* tag) { > + if (is_debug_tag_set(tag)) { > +# if TS_USE_POSIX_CAP > + cap_t caps = cap_get_proc(); > + char* caps_text = cap_to_text(caps, 0); > +# endif > + > + Debug(tag, > + "uid=%u, gid=%u, euid=%u, egid=%u" > +# if TS_USE_POSIX_CAP > + ", caps %s thread 0x%x", > +# endif > + (unsigned)getuid(), (unsigned)getgid(), > + (unsigned)geteuid(), (unsigned)getegid() > +# if TS_USE_POSIX_CAP > + ,caps_text > + ,pthread_self() > +# endif > + ); > + > +# if TS_USE_POSIX_CAP > + cap_free(caps_text); > + cap_free(caps); > +# endif > + } > +} > + > +int > +PreserveCapabilities() { > + return prctl(PR_SET_KEEPCAPS, 1); > +} > + > +// Adjust the capabilities to only those needed. > +int > +RestrictCapabilities() { > + int zret = 0; // return value. > +#if TS_USE_POSIX_CAP > + cap_t caps = cap_get_proc(); // Only way to initialize it AFAICT.
No it's not, see below. > + cap_clear(caps); vsftpd uses this only to check if capabilities are available: #else /* VSF_SYSDEP_HAVE_LIBCAP */ static int do_checkcap(void) { cap_t current_caps = cap_get_proc(); cap_free(current_caps); if (current_caps != NULL) { return 1; } return 0; } > + // Capabilities we need. > + cap_value_t cap_list[] = { CAP_NET_ADMIN, CAP_NET_BIND_SERVICE }; > + static int const CAP_COUNT = sizeof(cap_list)/sizeof(*cap_list); > + > + cap_set_flag(caps, CAP_INHERITABLE, CAP_COUNT, cap_list, CAP_SET); > + cap_set_flag(caps, CAP_PERMITTED, CAP_COUNT, cap_list, CAP_SET); > + cap_set_flag(caps, CAP_EFFECTIVE, CAP_COUNT, cap_list, CAP_SET); > + zret = cap_set_proc(caps); > + cap_free(caps); Then uses this to set the caps needed: void vsf_sysdep_adopt_capabilities(unsigned int caps) { int retval; cap_value_t cap_value; cap_t adopt_caps = cap_init(); if (caps & kCapabilityCAP_CHOWN) { cap_value = CAP_CHOWN; cap_set_flag(adopt_caps, CAP_EFFECTIVE, 1, &cap_value, CAP_SET); cap_set_flag(adopt_caps, CAP_PERMITTED, 1, &cap_value, CAP_SET); } if (caps & kCapabilityCAP_NET_BIND_SERVICE) { cap_value = CAP_NET_BIND_SERVICE; cap_set_flag(adopt_caps, CAP_EFFECTIVE, 1, &cap_value, CAP_SET); cap_set_flag(adopt_caps, CAP_PERMITTED, 1, &cap_value, CAP_SET); } retval = cap_set_proc(adopt_caps); if (retval != 0) { die("cap_set_proc"); } cap_free(adopt_caps); } The only thing done differently is that it sets one CAP at a time. Also it neglects to set the CAPs inheritable, because it's not needed in this context it doesn't want its children to spawn daemons of their own. So your code is (mostly) fine, except for the error reported: WARNING: Unable to access() local state directory '/usr/local/ats_218/var/trafficserver': 13, Permission denied [Apr 26 16:26:06.570] Server {1079999328} WARNING: Please set 'proxy.config.local_state_dir' to allow statistics collection This either means we need to adapt the permissions in this directory, or we need to additionally give CAP_DAC_OVERRIDE. I'd rather not do the latter. > +#endif > + return zret; > +} > > Added: trafficserver/traffic/trunk/lib/ts/ink_cap.h > URL: > http://svn.apache.org/viewvc/trafficserver/traffic/trunk/lib/ts/ink_cap.h?rev=1096571&view=auto > ============================================================================== > --- trafficserver/traffic/trunk/lib/ts/ink_cap.h (added) > +++ trafficserver/traffic/trunk/lib/ts/ink_cap.h Mon Apr 25 19:29:02 > 2011 > @@ -0,0 +1,39 @@ > +/** @file > + > + POSIX Capability related utilities. > + > + @section license License > + > + Licensed to the Apache Software Foundation (ASF) under one > + or more contributor license agreements. See the NOTICE file > + distributed with this work for additional information > + regarding copyright ownership. The ASF licenses this file > + to you under the Apache License, Version 2.0 (the > + "License"); you may not use this file except in compliance > + with the License. You may obtain a copy of the License at > + > + http://www.apache.org/licenses/LICENSE-2.0 > + > + Unless required by applicable law or agreed to in writing, > software > + distributed under the License is distributed on an "AS IS" BASIS, > + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or > implied. > + See the License for the specific language governing permissions > and > + limitations under the License. > + > + */ > + > +#if !defined (_ink_cap_h_) > +#define _ink_cap_h_ > + > +/// Generate a debug message with the current capabilities for the > process. > +extern void DebugCapabilities( > + char const* tag ///< Debug message tag. > +); > +/// Set capabilities to persist across change of user id. > +/// @return 0 on success, non-zero otherwise. > +extern int PreserveCapabilities(); > +/// Initialize and restrict the capabilities of a thread. > +/// @return 0 on success, non-zero otherwise. > +extern int RestrictCapabilities(); > + > +#endif > > Modified: trafficserver/traffic/trunk/proxy/Main.cc > URL: > http://svn.apache.org/viewvc/trafficserver/traffic/trunk/proxy/Main.cc?rev=1096571&r1=1096570&r2=1096571&view=diff > ============================================================================== > --- trafficserver/traffic/trunk/proxy/Main.cc (original) > +++ trafficserver/traffic/trunk/proxy/Main.cc Mon Apr 25 19:29:02 > 2011 > @@ -47,10 +47,6 @@ extern "C" int plock(int); > #include <mcheck.h> > #endif > > -#if TS_USE_POSIX_CAP > -#include <sys/capability.h> > -#endif > - > #include "Main.h" > #include "signals.h" > #include "Error.h" > @@ -95,6 +91,8 @@ extern "C" int plock(int); > > #include "I_Tasks.h" > > +#include <ts/ink_cap.h> > + > #if TS_HAS_PROFILER > #include <google/profiler.h> > #endif > @@ -1061,23 +1059,6 @@ init_core_size() > } > } > > -#if TS_USE_POSIX_CAP > -// Restore the effective capabilities that we need. > -int > -restoreCapabilities() { > - int zret = 0; // return value. > - cap_t cap_set = cap_get_proc(); // current capabilities > - // Capabilities to restore. > - cap_value_t cap_list[] = { CAP_NET_ADMIN, CAP_NET_BIND_SERVICE }; > - static int const CAP_COUNT = sizeof(cap_list)/sizeof(*cap_list); > - > - cap_set_flag(cap_set, CAP_EFFECTIVE, CAP_COUNT, cap_list, > CAP_SET); > - zret = cap_set_proc(cap_set); > - cap_free(cap_set); > - return zret; > -} > -#endif > - > static void > adjust_sys_settings(void) > { > @@ -1110,9 +1091,6 @@ adjust_sys_settings(void) > #endif > > #endif // linux check > -#if TS_USE_POSIX_CAP > - restoreCapabilities(); > -#endif > } > > struct ShowStats: public Continuation > @@ -1659,6 +1637,26 @@ main(int argc, char **argv) > if (!num_task_threads) > TS_ReadConfigInteger(num_task_threads, > "proxy.config.task_threads"); > > + // change the user of the process > + // do this before we start threads so we control the user id of > the > + // threads (rather than have it change asynchronously during > thread > + // execution). We also need to do this before we fiddle with > capabilities > + // as those are thread local and if we change the user id it will > + // modified the capabilities in other threads, breaking things. > + const long max_login = sysconf(_SC_LOGIN_NAME_MAX) <= 0 ? > _POSIX_LOGIN_NAME_MAX : sysconf(_SC_LOGIN_NAME_MAX); > + char *user = (char *)xmalloc(max_login); > + *user = '\0'; > + if ((TS_ReadConfigString(user, "proxy.config.admin.user_id", > + max_login) == REC_ERR_OKAY) && > + user[0] != '\0' && > + strcmp(user, "#-1")) { > + PreserveCapabilities(); > + change_uid_gid(user); > + RestrictCapabilities(); > + xfree(user); > + } > + DebugCapabilities("server"); > + > // This call is required for win_9xMe > //without this this_ethread() is failing when > //start_HttpProxyServer is called from main thread > @@ -1941,22 +1939,6 @@ main(int argc, char **argv) > run_AutoStop(); > } > > - // change the user of the process > - const long max_login = sysconf(_SC_LOGIN_NAME_MAX) <= 0 ? > _POSIX_LOGIN_NAME_MAX : sysconf(_SC_LOGIN_NAME_MAX); > - char *user = (char *)xmalloc(max_login); > - *user = '\0'; > - if ((TS_ReadConfigString(user, "proxy.config.admin.user_id", > - max_login) == REC_ERR_OKAY) && > - user[0] != '\0' && > - strcmp(user, "#-1")) { > - change_uid_gid(user); > - xfree(user); > - } > - Debug("server", > - "running as uid=%u, gid=%u, effective uid=%u, gid=%u", > - (unsigned)getuid(), (unsigned)getgid(), > - (unsigned)geteuid(), (unsigned)getegid()); > - > this_thread()->execute(); > } > > > Modified: trafficserver/traffic/trunk/proxy/http/HttpSM.cc > URL: > http://svn.apache.org/viewvc/trafficserver/traffic/trunk/proxy/http/HttpSM.cc?rev=1096571&r1=1096570&r2=1096571&view=diff > ============================================================================== > --- trafficserver/traffic/trunk/proxy/http/HttpSM.cc (original) > +++ trafficserver/traffic/trunk/proxy/http/HttpSM.cc Mon Apr 25 > 19:29:02 2011 > @@ -4396,17 +4396,15 @@ void > HttpSM::mark_host_failure(HostDBInfo * info, time_t time_down) > { > if (info->app.http_data.last_failure == 0) { > - int url_len; > - char *url_str; > - > - URL *url = t_state.hdr_info.client_request.url_get(); > - url_str = url->string_get(&t_state.arena, &url_len); > + char *url_str = > t_state.hdr_info.client_request.url_string_get(&t_state.arena, 0); > Log::error("CONNECT: could not connect to %u.%u.%u.%u " > "for '%s' (setting last failure time)", > ((unsigned char *) &t_state.current.server->ip)[0], > ((unsigned char *) &t_state.current.server->ip)[1], > ((unsigned char *) &t_state.current.server->ip)[2], > - ((unsigned char *) &t_state.current.server->ip)[3], > url_str); > + ((unsigned char *) &t_state.current.server->ip)[3], > + url_str ? url_str : "<none>" > + ); > if (url_str) > t_state.arena.str_free(url_str); > } > > Modified: trafficserver/traffic/trunk/proxy/http/HttpTransact.cc > URL: > http://svn.apache.org/viewvc/trafficserver/traffic/trunk/proxy/http/HttpTransact.cc?rev=1096571&r1=1096570&r2=1096571&view=diff > ============================================================================== > --- trafficserver/traffic/trunk/proxy/http/HttpTransact.cc (original) > +++ trafficserver/traffic/trunk/proxy/http/HttpTransact.cc Mon Apr 25 > 19:29:02 2011 > @@ -832,7 +832,6 @@ HttpTransact::EndRemapRequest(State* s) > Debug("http_trans", "START HttpTransact::EndRemapRequest"); > > HTTPHdr *incoming_request = &s->hdr_info.client_request; > - //URL *url = incoming_request->url_get(); > int method = incoming_request->method_get_wksidx(); > int host_len; > const char *host = incoming_request->host_get(&host_len); > @@ -955,12 +954,6 @@ done: > TRANSACT_RETURN(PROXY_INTERNAL_CACHE_NOOP, NULL); > } > > - if (s->reverse_proxy) { > - Debug("url_rewrite", "s->reverse_proxy is true"); > - } else { > - Debug("url_rewrite", "s->reverse_proxy is false"); > - } > - > if (is_debug_tag_set("http_chdr_describe") || > is_debug_tag_set("http_trans") || > is_debug_tag_set("url_rewrite")) { > Debug("http_trans", "After Remapping:"); > obj_describe(s->hdr_info.client_request.m_http, 1); > @@ -3769,8 +3762,7 @@ HttpTransact::retry_server_connection_no > ink_debug_assert(s->current.attempts <= max_retries); > ink_debug_assert(s->current.server->connect_failure != 0); > > - URL *url = s->hdr_info.client_request.url_get(); > - char *url_string = url->valid()? url->string_get(&s->arena) : > NULL; > + char *url_string = > s->hdr_info.client_request.url_string_get(&s->arena) : NULL; > > Debug("http_trans", "[%d] failed to connect [%d] to %u.%u.%u.%u", > s->current.attempts, conn_state, > PRINT_IP(s->current.server->ip)); > > > -- Igor Galić Tel: +43 (0) 664 886 22 883 Mail: i.ga...@brainsware.org URL: http://brainsware.org/