httpd-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Randy Terbush <ra...@zyzzyva.com>
Subject SetUID
Date Sun, 31 Mar 1996 23:03:25 GMT

OK. So I'm stubborn.... :-)

I have implemented a feature which allows you to set the owner
and group for CGI execution based on 'User' and 'Group' config
parameters in the VirtualHost setup.

I'm off to watch Nova and wanted to fire this at the group.
Let me know what you think.

BTW - Behaviour is enabled with -S runtime flag. That, as all of
it, is open for debate.


Index: src/Configuration.tmpl
===================================================================
RCS file: /export/home/cvs/apache/src/Configuration.tmpl,v
retrieving revision 1.9
diff -c -r1.9 Configuration.tmpl
*** Configuration.tmpl	1996/03/25 11:35:11	1.9
--- Configuration.tmpl	1996/03/31 22:57:25
***************
*** 20,26 ****
  # CC= cc
  # For Suns or other non-ANSI platforms. Please make sure your gcc is
  # 2.0 or later, as 1.40 seems to create bad code for the Sun 4.
! CC= gcc
  
  # CFLAGS, compile flags.
  
--- 20,26 ----
  # CC= cc
  # For Suns or other non-ANSI platforms. Please make sure your gcc is
  # 2.0 or later, as 1.40 seems to create bad code for the Sun 4.
! CC= gcc -Wall
  
  # CFLAGS, compile flags.
  
Index: src/Makefile.tmpl
===================================================================
RCS file: /export/home/cvs/apache/src/Makefile.tmpl,v
retrieving revision 1.8
diff -c -r1.8 Makefile.tmpl
*** Makefile.tmpl	1996/03/30 15:31:13	1.8
--- Makefile.tmpl	1996/03/31 22:57:26
***************
*** 3,10 ****
  # This is combined with the information in the "Configuration" file
  # by the configure script to make the actual Makefile.
  
! OBJS= alloc.o http_main.o http_core.o http_config.o http_request.o \
!   http_log.o http_protocol.o rfc1413.o util.o util_script.o modules.o buff.o\
    md5c.o util_md5.o explain.o $(MODULES)
  
  .c.o:
--- 3,10 ----
  # This is combined with the information in the "Configuration" file
  # by the configure script to make the actual Makefile.
  
! OBJS= alloc.o http_main.o http_core.o http_config.o http_request.o http_exec.o \
!   http_log.o http_protocol.o rfc1413.o util.o util_script.o modules.o buff.o \
    md5c.o util_md5.o explain.o $(MODULES)
  
  .c.o:
Index: src/http_core.c
===================================================================
RCS file: /export/home/cvs/apache/src/http_core.c,v
retrieving revision 1.8
diff -c -r1.8 http_core.c
*** http_core.c	1996/03/30 07:16:40	1.8
--- http_core.c	1996/03/31 22:57:39
***************
*** 577,588 ****
  
  char *set_user (cmd_parms *cmd, void *dummy, char *arg) {
      user_name = pstrdup (cmd->pool, arg);
!     user_id = uname2id (user_name);
      return NULL;
  }
  
  char *set_group (cmd_parms *cmd, void *dummy, char *arg) {
!     group_id = gname2id(arg);
      return NULL;
  }
  
--- 577,588 ----
  
  char *set_user (cmd_parms *cmd, void *dummy, char *arg) {
      user_name = pstrdup (cmd->pool, arg);
!     cmd->server->server_uid = uname2id (user_name);
      return NULL;
  }
  
  char *set_group (cmd_parms *cmd, void *dummy, char *arg) {
!     cmd->server->server_gid = gname2id(arg);
      return NULL;
  }
  
***************
*** 732,739 ****
  { "ServerType", server_type, NULL, RSRC_CONF, TAKE1,"'inetd' or 'standalone'"},
  { "Port", server_port, NULL, RSRC_CONF, TAKE1, "a TCP port number"},
  { "HostnameLookups", set_hostname_lookups, NULL, ACCESS_CONF|RSRC_CONF, FLAG, NULL },
! { "User", set_user, NULL, RSRC_CONF, TAKE1, "a username"},
! { "Group", set_group, NULL, RSRC_CONF, TAKE1, "a group name"},
  { "ServerAdmin", set_server_string_slot,
    (void *)XtOffsetOf (server_rec, server_admin), RSRC_CONF, TAKE1,
    "The email address of the server administrator" },
--- 732,739 ----
  { "ServerType", server_type, NULL, RSRC_CONF, TAKE1,"'inetd' or 'standalone'"},
  { "Port", server_port, NULL, RSRC_CONF, TAKE1, "a TCP port number"},
  { "HostnameLookups", set_hostname_lookups, NULL, ACCESS_CONF|RSRC_CONF, FLAG, NULL },
! { "User", set_user, NULL, RSRC_CONF, TAKE1, "effective user id for this server"},
! { "Group", set_group, NULL, RSRC_CONF, TAKE1, "effective group id for this server"},
  { "ServerAdmin", set_server_string_slot,
    (void *)XtOffsetOf (server_rec, server_admin), RSRC_CONF, TAKE1,
    "The email address of the server administrator" },
Index: src/http_main.c
===================================================================
RCS file: /export/home/cvs/apache/src/http_main.c,v
retrieving revision 1.17
diff -c -r1.17 http_main.c
*** http_main.c	1996/03/30 16:43:50	1.17
--- http_main.c	1996/03/31 22:57:43
***************
*** 145,150 ****
--- 145,151 ----
   */
  
  int one_process = 0;
+ int really_stupid = 0;
  
  #if defined(FCNTL_SERIALIZED_ACCEPT)
  static struct flock lock_it = { F_WRLCK, 0, 0, 0 };
***************
*** 1071,1081 ****
      update_child_status (child_num, SERVER_READY);
  
      /* Only try to switch if we're running as root */
!     if(!geteuid() && setuid(user_id) == -1) {
          log_unixerr("setuid", NULL, "unable to change uid", server_conf);
  	exit (1);
      }
! 
  #ifdef NEXT
      setjmp(jmpbuffer);
  #else
--- 1072,1083 ----
      update_child_status (child_num, SERVER_READY);
  
      /* Only try to switch if we're running as root */
!     if(!really_stupid && !geteuid() && setuid(user_id) == -1) {
! 	set_group_privs();
          log_unixerr("setuid", NULL, "unable to change uid", server_conf);
  	exit (1);
      }
!     
  #ifdef NEXT
      setjmp(jmpbuffer);
  #else
***************
*** 1392,1398 ****
      strcpy (server_root, HTTPD_ROOT);
      strcpy (server_confname, SERVER_CONFIG_FILE);
  
!     while((c = getopt(argc,argv,"Xd:f:v")) != -1) {
          switch(c) {
            case 'd':
              strcpy (server_root, optarg);
--- 1394,1400 ----
      strcpy (server_root, HTTPD_ROOT);
      strcpy (server_confname, SERVER_CONFIG_FILE);
  
!     while((c = getopt(argc,argv,"SXd:f:v")) != -1) {
          switch(c) {
            case 'd':
              strcpy (server_root, optarg);
***************
*** 1405,1410 ****
--- 1407,1415 ----
              exit(1);
  	  case 'X':
  	    ++one_process;	/* Weird debugging mode. */
+ 	    break;
+ 	  case 'S':
+ 	    ++really_stupid;	/* Don't run this if you have half a brain */
  	    break;
            case '?':
              usage(argv[0]);
Index: src/httpd.h
===================================================================
RCS file: /export/home/cvs/apache/src/httpd.h,v
retrieving revision 1.14
diff -c -r1.14 httpd.h
*** httpd.h	1996/03/31 01:07:00	1.14
--- httpd.h	1996/03/31 22:57:50
***************
*** 238,243 ****
--- 238,244 ----
  #define BAD_GATEWAY 502
  #define SERVICE_UNAVAILABLE 503
  #define RESPONSE_CODES 10
+ #define CANNOT_EXEC 1000
  
  #define METHODS 5
  #define M_GET 0
***************
*** 425,467 ****
  
  struct server_rec {
  
!   server_rec *next;
    
!   /* Full locations of server config info */
    
!   char *srm_confname;
!   char *access_confname;
    
!   /* Contact information */
    
!   char *server_admin;
!   char *server_hostname;
!   short port;                    /* for redirects, etc. */
    
!   /* Log files --- note that transfer log is now in the modules... */
    
!   char *error_fname;
!   FILE *error_log;
!   
!   /* Module-specific configuration for server, and defaults... */
  
!   int is_virtual;               /* true if this is the virtual server */
!   void *module_config;		/* Config vector containing pointers to
  				 * modules' per-server config structures.
  				 */
!   void *lookup_defaults;	/* MIME type info, etc., before we start
  				 * checking per-directory info.
  				 */
!   /* Transaction handling */
  
!   struct in_addr host_addr;	/* The bound address, for this server */
!   short host_port;              /* The bound port, for this server */
!   int timeout;			/* Timeout, in seconds, before we give up */
!   int keep_alive_timeout;	/* Seconds we'll wait for another request */
!   int keep_alive;		/* Maximum requests per connection */
  
!   char *names;			/* Wildcarded names for HostAlias servers */
!   char *virthost;		/* The name given in <VirtualHost> */
  };
  
  /* These are more like real hosts than virtual hosts */
--- 426,473 ----
  
  struct server_rec {
  
!     server_rec *next;
    
!     /* Full locations of server config info */
    
!     char *srm_confname;
!     char *access_confname;
    
!     /* Contact information */
    
!     char *server_admin;
!     char *server_hostname;
!     short port;                    /* for redirects, etc. */
    
!     /* Log files --- note that transfer log is now in the modules... */
    
!     char *error_fname;
!     FILE *error_log;
! 
!     /* Module-specific configuration for server, and defaults... */
  
!     int is_virtual;             /* true if this is the virtual server */
!     void *module_config;	/* Config vector containing pointers to
  				 * modules' per-server config structures.
  				 */
!     void *lookup_defaults;	/* MIME type info, etc., before we start
  				 * checking per-directory info.
  				 */
!     /* Transaction handling */
! 
!     struct in_addr host_addr;	/* The bound address, for this server */
!     short host_port;		/* The bound port, for this server */
!     int timeout;		/* Timeout, in seconds, before we give up */
!     int keep_alive_timeout;	/* Seconds we'll wait for another request */
!     int keep_alive;		/* Maximum requests per connection */
! 
!     char *names;		/* Wildcarded names for HostAlias servers */
!     char *virthost;		/* The name given in <VirtualHost> */
  
!     /* effective user/group id */
  
!     pid_t server_uid;
!     gid_t server_gid;
  };
  
  /* These are more like real hosts than virtual hosts */
***************
*** 518,524 ****
  uid_t uname2id(char *name);
  gid_t gname2id(char *name);
  int is_directory(char *name);
! int can_exec(struct stat *);     
  void chdir_file(char *file);
       
  char *get_local_host(pool *);
--- 524,531 ----
  uid_t uname2id(char *name);
  gid_t gname2id(char *name);
  int is_directory(char *name);
! int can_exec(request_rec *r);     
! void do_exec(request_rec *r);     
  void chdir_file(char *file);
       
  char *get_local_host(pool *);
Index: src/mod_cgi.c
===================================================================
RCS file: /export/home/cvs/apache/src/mod_cgi.c,v
retrieving revision 1.6
diff -c -r1.6 mod_cgi.c
*** mod_cgi.c	1996/03/31 01:07:01	1.6
--- mod_cgi.c	1996/03/31 22:57:58
***************
*** 74,90 ****
  #include "http_log.h"
  #include "util_script.h"
  
- /* KLUDGE --- for back-combatibility, we don't have to check ExecCGI
-  * in ScriptAliased directories, which means we need to know if this
-  * request came through ScriptAlias or not... so the Alias module
-  * leaves a note for us.
-  */
- 
- int is_scriptaliased (request_rec *r)
- {
-     char *t = table_get (r->notes, "alias-forced-type");
-     return t && (!strcmp (t, "cgi-script"));
- }
  
  /****************************************************************
   *
--- 74,79 ----
***************
*** 102,108 ****
  {
      struct cgi_child_stuff *cld = (struct cgi_child_stuff *)child_stuff;
      request_rec *r = cld->r;
-     char *argv0 = cld->argv0;
      int nph = cld->nph;
  
  #ifdef DEBUG_CGI    
--- 91,96 ----
***************
*** 119,124 ****
--- 107,113 ----
      char err_string[HUGE_STRING_LEN];
      
  #ifdef DEBUG_CGI    
+     char *argv0 = cld->argv0;
      fprintf (dbg, "Attempting to exec %s as %sCGI child (argv0 = %s)\n",
  	    r->filename, nph ? "NPH " : "", argv0);
  #endif    
***************
*** 141,191 ****
      /* Transumute outselves into the script.
       * NB only ISINDEX scripts get decoded arguments.
       */
!     
      cleanup_for_exec();
!     
! #ifdef __EMX__    
!     if((!r->args) || (!r->args[0]) || (ind(r->args,'=') >= 0)) {
!             int emxloop;
!             char *emxtemp;
! 
!             /* For OS/2 place the variables in the current
!             enviornment then it will be inherited. This way
!             the program will also get all of OS/2's other SETs. */
!             for (emxloop=0; ((emxtemp = env[emxloop]) != NULL); emxloop++)
!                 putenv(emxtemp);
!                 
!             if (strstr(strupr(r->filename), ".CMD") > 0) {
!                 /* Special case to allow use of REXX commands as scripts. */
!                 os2pathname(r->filename);
!                 execl("CMD.EXE", "CMD.EXE", "/C", r->filename, NULL);
!             } else {
!                 execl(r->filename, argv0, NULL);
!             }
!     } else {
!             int emxloop;
!             char *emxtemp;
!             
!             /* For OS/2 place the variables in the current
!             enviornment then it will be inherited. This way
!             the program will also get all of OS/2's other SETs. */
!             for (emxloop=0; ((emxtemp = env[emxloop]) != NULL); emxloop++)
!                 putenv(emxtemp);
!                 
!             if (strstr(strupr(r->filename), ".CMD") > 0) {
!                 /* Special case to allow use of REXX commands as scripts. */
!                 os2pathname(r->filename);
!                 execv("CMD.EXE", create_argv_cmd(r->pool, argv0, r->args, r->filename));
!             } else {
!                 execv(r->filename, create_argv(r->pool, argv0, r->args));
!             }
!     }
! #else
!     if((!r->args) || (!r->args[0]) || (ind(r->args,'=') >= 0)) 
!         execle(r->filename, argv0, NULL, env);
!     else 
!         execve(r->filename, create_argv(r->pool, argv0, r->args), env);
! #endif        
  
      /* Uh oh.  Still here.  Where's the kaboom?  There was supposed to be an
       * EARTH-shattering kaboom!
--- 130,139 ----
      /* Transumute outselves into the script.
       * NB only ISINDEX scripts get decoded arguments.
       */
! 
      cleanup_for_exec();
! 
!     do_exec(r);
  
      /* Uh oh.  Still here.  Where's the kaboom?  There was supposed to be an
       * EARTH-shattering kaboom!
***************
*** 207,216 ****
  int cgi_handler (request_rec *r)
  {
      int nph;
      char *argv0;
      FILE *script_out, *script_in;
      char argsbuffer[HUGE_STRING_LEN];
-     int is_included = !strcmp (r->protocol, "INCLUDED");
      char *lenp = table_get (r->headers_in, "Content-length");
  
      struct cgi_child_stuff cld;
--- 155,164 ----
  int cgi_handler (request_rec *r)
  {
      int nph;
+     int exec_check;
      char *argv0;
      FILE *script_out, *script_in;
      char argsbuffer[HUGE_STRING_LEN];
      char *lenp = table_get (r->headers_in, "Content-length");
  
      struct cgi_child_stuff cld;
***************
*** 221,255 ****
  
      nph = !(strncmp(argv0,"nph-",4));
      
-     if (!(allow_options (r) & OPT_EXECCGI) && !is_scriptaliased (r)) {
-         log_reason("Options ExecCGI is off in this directory", r->filename, r);
- 	return FORBIDDEN;
-     }
-     if (nph && is_included) {
-         log_reason("attempt to include NPH CGI script", r->filename, r);
- 	return FORBIDDEN;
-     }
-     
-     if (S_ISDIR(r->finfo.st_mode)) {
-         log_reason("attempt to invoke directory as script", r->filename, r);
- 	return FORBIDDEN;
-     }
-     if (r->finfo.st_mode == 0) {
-         log_reason("script not found or unable to stat", r->filename, r);
- 	return NOT_FOUND;
-     }
-     if(!can_exec(&r->finfo)) {
-         log_reason("file permissions deny server execution", r->filename, r);
-         return FORBIDDEN;
-     }
-     if ((r->method_number == M_POST || r->method_number == M_PUT)
- 	&& !lenp) {
-         log_reason("POST or PUT without Content-length:", r->filename, r);
- 	return BAD_REQUEST;
-     }
- 
-     add_common_vars (r);
      cld.argv0 = argv0; cld.r = r; cld.nph = nph;
      
  #ifdef __EMX__
      if (r->method_number == M_POST || r->method_number == M_PUT) {
--- 169,180 ----
  
      nph = !(strncmp(argv0,"nph-",4));
      
      cld.argv0 = argv0; cld.r = r; cld.nph = nph;
+     
+     add_common_vars (r);
+ 
+     if ((exec_check = can_exec(r)))
+ 	return (exec_check);
      
  #ifdef __EMX__
      if (r->method_number == M_POST || r->method_number == M_PUT) {
Index: src/mod_include.c
===================================================================
RCS file: /export/home/cvs/apache/src/mod_include.c,v
retrieving revision 1.6
diff -c -r1.6 mod_include.c
*** mod_include.c	1996/03/31 01:07:02	1.6
--- mod_include.c	1996/03/31 22:58:07
***************
*** 436,449 ****
  void include_cmd_child (void *arg)
  {
      request_rec *r =  ((include_cmd_arg *)arg)->r;
-     char *s = ((include_cmd_arg *)arg)->s;
      table *env = r->subprocess_env;
  #ifdef DEBUG_INCLUDE_CMD    
  #ifdef __EMX__
      /* under OS/2 /dev/tty is referenced as con */
      FILE *dbg = fopen ("con", "w");
  #else
!         FILE *dbg = fopen ("/dev/tty", "w");
  #endif    
  #endif    
      char err_string [MAX_STRING_LEN];
--- 436,448 ----
  void include_cmd_child (void *arg)
  {
      request_rec *r =  ((include_cmd_arg *)arg)->r;
      table *env = r->subprocess_env;
  #ifdef DEBUG_INCLUDE_CMD    
  #ifdef __EMX__
      /* under OS/2 /dev/tty is referenced as con */
      FILE *dbg = fopen ("con", "w");
  #else
!     FILE *dbg = fopen ("/dev/tty", "w");
  #endif    
  #endif    
      char err_string [MAX_STRING_LEN];
***************
*** 478,485 ****
      fprintf (dbg, "Attempting to exec '%s'\n", s);
  #endif    
      cleanup_for_exec();
!     execle(SHELL_PATH, SHELL_PATH, "-c", s, NULL,
! 	   create_environment (r->pool, env));
      
      /* Oh, drat.  We're still here.  The log file descriptors are closed,
       * so we have to whimper a complaint onto stderr...
--- 477,483 ----
      fprintf (dbg, "Attempting to exec '%s'\n", s);
  #endif    
      cleanup_for_exec();
!     do_exec(r);
      
      /* Oh, drat.  We're still here.  The log file descriptors are closed,
       * so we have to whimper a complaint onto stderr...
Index: src/util.c
===================================================================
RCS file: /export/home/cvs/apache/src/util.c,v
retrieving revision 1.6
diff -c -r1.6 util.c
*** util.c	1996/03/28 07:59:32	1.6
--- util.c	1996/03/31 22:58:34
***************
*** 729,749 ****
      else return 0;
  }
  
- int can_exec(struct stat *finfo) {
- #ifdef __EMX__
-     /* OS/2 dosen't have Users and Groups */
-     return (finfo->st_mode & S_IEXEC);
- #else    
-     if(user_id == finfo->st_uid)
-         if(finfo->st_mode & S_IXUSR)
-             return 1;
-     if(group_id == finfo->st_gid)
-         if(finfo->st_mode & S_IXGRP)
-             return 1;
-     return (finfo->st_mode & S_IXOTH);
- #endif    
- }
- 
  #ifdef NEED_STRDUP
  char *strdup (char *str)
  {
--- 729,734 ----






Mime
View raw message