Ticket #6264: 0001-Make-obfsproxy-drop-privileges-if-requested.patch

File 0001-Make-obfsproxy-drop-privileges-if-requested.patch, 8.2 KB (added by dazo, 7 years ago)
  • configure.ac

    From 7b8b4b2ceb081d537b437c3f80b18cd7b6dd9668 Mon Sep 17 00:00:00 2001
    From: David Sommerseth <dazo@users.sourceforge.net>
    Date: Sat, 30 Jun 2012 18:47:37 +0200
    Subject: [PATCH 1/2] Make obfsproxy drop privileges if requested
    
    Added --user and --group arguments which will make obfsproxy drop privileges
    and switch to the given user/group.
    
    The code for droping privileges is shamelessly taken from the Tor project and
    adopted to obfsproxy.  The switch_id() function in src/common/compat.c was used.
    
    Signed-off-by: David Sommerseth <dazo@users.sourceforge.net>
    ---
     configure.ac   |    3 +
     src/external.c |   16 +++++++-
     src/main.c     |  120 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
     src/managed.c  |   10 +++++
     4 files changed, 147 insertions(+), 2 deletions(-)
    
    diff --git a/configure.ac b/configure.ac
    index 56c365b..04b7e4c 100644
    a b AC_CHECK_HEADERS([sys/types.h]) 
    2424AC_CHECK_HEADERS([sys/stat.h])
    2525AC_CHECK_HEADERS([fcntl.h])
    2626AC_CHECK_HEADERS([netinet/in.h])
     27AC_CHECK_HEADERS([pwd.h])
     28AC_CHECK_HEADERS([grp.h])
     29
    2730
    2831### Compiler Hardening ###
    2932AX_ENABLE_HARDENING
  • src/external.c

    diff --git a/src/external.c b/src/external.c
    index 76abf56..f3c334b 100644
    a b  
    1919
    2020#include <event2/event.h>
    2121
     22extern struct passwd * runas_user;
     23extern struct group * runas_group;
     24int drop_privileges();
     25
    2226/**
    2327   Launch external proxy.
    2428*/
    launch_external_proxy(const char *const *begin) 
    2731{
    2832  smartlist_t *configs = smartlist_create();
    2933  const char *const *end;
    30 
     34  int rc = -1;
    3135
    3236  /* Find the subsets of argv that define each configuration.
    3337     Each configuration's subset consists of the entries in argv from
    launch_external_proxy(const char *const *begin) 
    7377  SMARTLIST_FOREACH(configs, config_t *, cfg, {
    7478    if (!open_listeners(get_event_base(), cfg)) {
    7579      log_error("Failed to open listeners for configuration %d", cfg_sl_idx+1);
     80      goto done;
    7681    }
    7782  });
    7883
     84  if( runas_user || runas_group ) {
     85    if( drop_privileges() < 0 )
     86      goto done;
     87  }
     88
    7989  /* We are go for launch. */
    8090  event_base_dispatch(get_event_base());
     91  rc = 0;
    8192
     93 done:
    8294  /* Cleanup and exit! */
    8395  obfsproxy_cleanup();
    8496
    8597  SMARTLIST_FOREACH(configs, config_t *, cfg, config_free(cfg));
    8698  smartlist_free(configs);
    8799
    88   return 0;
     100  return rc;
    89101}
  • src/main.c

    diff --git a/src/main.c b/src/main.c
    index 71c688c..cb092a1 100644
    a b  
    2929#include <stdio.h>
    3030
    3131#ifdef HAVE_UNISTD_H
     32#define _GNU_SOURCE
    3233#include <unistd.h>
     34#include <pwd.h>
     35#include <grp.h>
    3336#endif
    3437
    3538#ifdef HAVE_SYS_STAT_H
    static struct event *sig_int; 
    5861static struct event *sig_term;
    5962static struct event *heartbeat;
    6063
     64struct passwd *runas_user = NULL;
     65struct group *runas_group = NULL;
     66
    6167/* Pluggable transport proxy mode. ('External' or 'Managed') */
    6268static int is_external_proxy=1;
    6369/* Whether to scrub connection addresses -- on by default */
    write_pid(void) 
    189195  return 0;
    190196}
    191197#endif /* HAVE_FCNTL_H */
     198
     199
     200/**
     201 * Drop all privileges permanently to the user/group given by the --user and --group arguments
     202 *
     203 * Shamelessly stolen from tor.git/src/common/compat.c:switch_id() and adopted to obfsproxy
     204 */
     205int
     206drop_privileges(void)
     207{
     208#ifndef _WIN32
     209  uid_t old_uid;
     210  gid_t old_gid, new_gid;
     211
     212  /* Get old UID/GID to check if we changed correctly */
     213  old_uid = getuid();
     214  old_gid = getgid();
     215
     216  if (runas_user && old_uid == runas_user->pw_uid) {
     217    log_warn("obfsproxy is already running as %s.  You do not need "
     218             "the --user option if you are already running as the user "
     219             "you want to be.", runas_user->pw_name);
     220  } else if (old_uid > 0) {
     221    log_error("If you set the --user or --group option, you must start obfsproxy"
     222             " as root.");
     223  }
     224
     225  /* If only --user is given, switch that users group as well */
     226  new_gid = (!runas_group ? runas_user->pw_gid : runas_group->gr_gid);
     227
     228  /* Properly switch egid,gid,euid,uid here or bail out */
     229  if (setgroups(1, &new_gid) == 0) {
     230    if (setegid(new_gid)) {
     231      log_warn("Error setting egid to %d: %s",
     232               (int)new_gid, strerror(errno));
     233      return -1;
     234    }
     235
     236    if (setgid(new_gid)) {
     237      log_warn("Error setting gid to %d: %s",
     238               (int)new_gid, strerror(errno));
     239      return -1;
     240    }
     241  } else {
     242    log_warn("Error setting groups to gid %d: \"%s\".",
     243             (int)new_gid, strerror(errno));
     244    return -1;
     245  }
     246
     247  if (runas_user) {
     248    if (setuid(runas_user->pw_uid)) {
     249      log_warn("Error setting configured uid to %s (%d): %s",
     250               runas_user->pw_name, (int)runas_user->pw_uid, strerror(errno));
     251      return -1;
     252    }
     253
     254    if (seteuid(runas_user->pw_uid)) {
     255      log_warn("Error setting configured euid to %s (%d): %s",
     256               runas_user->pw_name, (int)runas_user->pw_uid, strerror(errno));
     257      return -1;
     258    }
     259
     260#if !defined(CYGWIN) && !defined(__CYGWIN__)
     261    if (runas_user->pw_uid) {
     262      /* Try changing UID/EUID back to the old group - should not be allowed */
     263      if (runas_user->pw_uid != old_uid &&
     264          (setuid(old_uid) != -1 || seteuid(old_uid) != -1)) {
     265        log_warn("Was able to restore user credentials even after "
     266                 "switching UID: this means that the setuid code didn't work.");
     267        return -1;
     268      }
     269    }
     270#endif
     271  }
     272
     273#if !defined(CYGWIN) && !defined(__CYGWIN__)
     274   /* Try changing GID/EGID back to the old group - should not be allowed */
     275  if (getuid() != 0 && new_gid != old_gid &&
     276      (setgid(old_gid) != -1 || setegid(old_gid) != -1)) {
     277    log_warn("Was able to restore group credentials even after "
     278             "switching GID: this means that the setgid code didn't work.");
     279    return -1;
     280  }
     281#endif
     282
     283  /* We've properly switched egid, gid, euid, uid, and supplementary groups if
     284   * we're here. */
     285
     286  if (runas_user) {
     287    log_info("Switched user to %d", getuid());
     288  }
     289  log_info("Switched group to %d", getgid());
     290
     291  return 0;
     292
     293#else
     294  log_warn("User specified but switching users is unsupported on your OS.");
     295  return -1;
     296#endif
     297}
    192298#endif /* HAVE_UNISTD_H */
    193299
    194300
    usage(void) 
    208314  fprintf(stderr, "\n* obfsproxy_args:\n"
    209315#ifdef HAVE_UNISTD_H
    210316          "--daemon ~ run as a daemon\n"
     317          "--user=<user name> ~ Run as this user\n"
     318          "--group=<group name> ~ Run as this group\n"
    211319#ifdef HAVE_FCNTL_H
    212320          "--pid-file=<file> ~ file where to write daemon PID\n"
    213321#endif /* HAVE_FCNTL_H */
    handle_obfsproxy_args(const char *const *argv) 
    350458#ifdef HAVE_UNISTD_H
    351459    } else if (!strncmp(argv[i], "--daemon", 8)) {
    352460      do_daemonize = 1;
     461    } else if (!strncmp(argv[i], "--user=", 7)) {
     462      runas_user = getpwnam(argv[i]+7);
     463      if (runas_user == NULL) {
     464        log_warn("Error setting configured user: %s not found", argv[i]+7);
     465        exit(1);
     466      }
     467    } else if (!strncmp(argv[i], "--group=", 8)) {
     468      runas_group = getgrnam(argv[i]+8);
     469      if (runas_group == NULL) {
     470        log_warn("Error setting configured group: %s not found", argv[i]+8);
     471        exit(1);
     472      }
    353473#ifdef HAVE_FCNTL_H
    354474    } else if (!strncmp(argv[i], "--pid-file=", 11)) {
    355475      pidfilename = strdup(argv[i]+11);
  • src/managed.c

    diff --git a/src/managed.c b/src/managed.c
    index 5542bb9..54e39e9 100644
    a b launch_listeners(const managed_proxy_t *proxy) 
    663663    return launch_client_listeners(proxy);
    664664}
    665665
     666extern struct passwd * runas_user;
     667extern struct group * runas_group;
     668int drop_privileges();
     669
    666670/**
    667671   This function fires up the managed proxy.
    668672   It first reads the environment that tor should have prepared, and then
    launch_listeners(const managed_proxy_t *proxy) 
    671675   Returns 0 if we managed to launch at least one proxy,
    672676   returns -1 if something went wrong or we didn't launch any proxies.
    673677*/
     678
    674679int
    675680launch_managed_proxy(void)
    676681{
    launch_managed_proxy(void) 
    692697  if (launch_listeners(proxy) < 0)
    693698    goto done;
    694699
     700  if( runas_user || runas_group ) {
     701    if( drop_privileges() < 0 )
     702      goto done;
     703  }
     704
    695705  /* Kickstart libevent */
    696706  event_base_dispatch(get_event_base());
    697707