Branch: Tag:

2001-08-24

2001-08-24 17:35:49 by Martin Stjernholm <mast@lysator.liu.se>

Added paranoia code to ensure that every handler thread has switched
euid properly, when that's been requested. This problem has been
observed with Pike 7.0 on Linux, but 7.2 works correctly.

Thanks to Alexander Demenshin <aldem-pike@aldem.net> for reporting this
security problem.

Rev: server/base_server/roxen.pike:1.715

6:   // Per Hedbor, Henrik Grubbström, Pontus Hagland, David Hedbor and others.   // ABS and suicide systems contributed freely by Francesco Chemolli    - constant cvs_version="$Id: roxen.pike,v 1.714 2001/08/24 13:19:30 mast Exp $"; + constant cvs_version="$Id: roxen.pike,v 1.715 2001/08/24 17:35:49 mast Exp $";      // The argument cache. Used by the image cache.   ArgCache argcache;
62:   #define DDUMP(X) sol( combine_path( __FILE__, "../../" + X ), dump )   static function sol = master()->set_on_load;    + #ifdef TEST_EUID_CHANGE + int test_euid_change; + #endif +    string query_configuration_dir()   {    return configuration_dir;
548: Inside #if defined(THREADS)
  {    THREAD_WERR("Handle thread ["+id+"] started");    mixed h, q; +  set_u_and_gid (1); + #ifdef TEST_EUID_CHANGE +  if (test_euid_change) { +  Stdio.File f = Stdio.File(); +  if (f->open ("rootonly", "r") && f->read()) +  werror ("Handler thread %d can read rootonly\n", id); +  else +  werror ("Handler thread %d can't read rootonly\n", id); +  } + #endif    while(1)    {    if(q=catch {
3356:    return locale->get();   }    - int set_u_and_gid() + int set_u_and_gid (void|int from_handler_thread)   //! Set the uid and gid to the ones requested by the user. If the   //! sete* functions are available, and the define SET_EFFECTIVE is   //! enabled, the euid and egid is set. This might be a minor security
3368: Inside #if undefined(__NT__)
   int uid, gid;    array pw;    +  if (from_handler_thread && geteuid()) { +  // The euid switch in the backend thread worked here too, so +  // there's no need to do anything. + #ifdef TEST_EUID_CHANGE +  werror ("euid change effective in handler thread.\n"); + #endif +  return 1; +  } +     u=query("User");    sscanf(u, "%s:%s", u, g);    if(strlen(u))    {    if(getuid())    { -  +  if (!from_handler_thread)    report_error(LOC_M(24, "It is only possible to change uid and gid "    "if the server is running as root.")+"\n");    } else { -  + #ifdef TEST_EUID_CHANGE +  if (Stdio.write_file ("rootonly", +  "Only root should be able to read this.\n", +  0600)) +  test_euid_change = 1; + #endif +     if (g) {   #if constant(getgrnam)    pw = getgrnam (g);
3405: Inside #if defined(THREADS)
     #ifdef THREADS    Thread.MutexKey mutex_key; +  object threads_disabled; +  if (!from_handler_thread) { +  // If this is necessary from every handler thread, these +  // things are thread local and thus are no locks necessary.    catch { mutex_key = euid_egid_lock->lock(); }; -  object threads_disabled = _disable_threads(); +  threads_disabled = _disable_threads(); +  }   #endif      #if constant(seteuid)
3430: Inside #if constant(setuid) and #if constant(setgid)
   g = 0;    }   # else +  if (!from_handler_thread)    report_warning(LOC_M(26, "Setting gid not supported on this system.")    +"\n");    g = 0;
3440:    report_error(LOC_M(27, "Failed to set uid.")+"\n");    u = 0;    } -  if (u) report_notice(CALL_M("setting_uid_gid_permanently", "eng") +  if (u && !from_handler_thread) +  report_notice(CALL_M("setting_uid_gid_permanently", "eng")    (uid, gid, u, g));   #else -  +  if (!from_handler_thread)    report_warning(LOC_M(28, "Setting uid not supported on this system.")    +"\n");    u = g = 0;
3458: Inside #if constant(seteuid) and #if constant(setegid)
   g = 0;    }   # else +  if (!from_handler_thread)    report_warning(LOC_M(30, "Setting effective gid not supported on "    "this system.")+"\n");    g = 0;
3468:    report_error(LOC_M(31, "Failed to set effective uid.")+"\n");    u = 0;    } -  if (u) report_notice(CALL_M("setting_uid_gid", "eng")(uid, gid, u, g)); +  if (u && !from_handler_thread) +  report_notice(CALL_M("setting_uid_gid", "eng")(uid, gid, u, g));   #else -  +  if (!from_handler_thread)    report_warning(LOC_M(32, "Setting effective uid not supported on "    "this system.")+"\n");    u = g = 0;
3991:    name_thread( backend_thread, "Backend" );   #endif /* THREADS */    + #ifdef TEST_EUID_CHANGE +  if (test_euid_change) { +  Stdio.File f = Stdio.File(); +  if (f->open ("rootonly", "r") && f->read()) +  werror ("Backend thread can read rootonly\n"); +  else +  werror ("Backend thread can't read rootonly\n"); +  } + #endif +     // Signals which cause a restart (exitcode != 0)    foreach( ({ "SIGINT", "SIGTERM" }), string sig)    catch( signal(signum(sig), async_sig_start(exit_when_done,0)) );