You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@httpd.apache.org by Stephen Andrew Misel <st...@interpath.net> on 1999/11/15 13:42:45 UTC

Setuid Apache?

Good morning.

I've developed a patch for 1.3.9 which will allow it to execute CGI's and serve
documents as the user the request came in for.

My new Apache has the SuEXEC User and Group directives enabled in httpd.conf but
instead of calling a wrapper for CGI's and serving documents as root or nobody, it
uses the User and Group directives to assume that user's identity to handle the
request.

The processes wait for connections as root, and once a connection has been made, it
calls setegid() and seteuid() for the User and Group specified in the conf file for
that VirtualHost.  If the request is a non CGI (or SSI, etc) the request is handled
and that process does a setegid() and seteuid() back to root to wait for the next
request.

In the event we're dealing with a CGI and need to fork(), the setegid() and
seteuid() are back to root, at which point it calls setgid() and setuid() to assume
the user's real identity (verses effective), and then forks off the child.  Of
course, when the request is complete, it assumes root again and waits in the free
pool.

I see the security implications here as minimal, as long as the server makes a
confirmation that it's uid/gid change was successful before serving documents or
running CGI's (otherwise they'd run as root, bad bad).  Am I correct?

I've been running this on development servers (Enterprise 450's) for some time on
both Apache 1.3.9 and StrongHold 2.4.2 with no problems.  Also, mod_frontpage (I
know how little we like to talk about it!) works flawlessly in this scenario.  It's
like each customer gets as many apache processes as they need, all running as them.
Also, I thought it was pretty spiffy to watch the processes with ps.  I can see them
running as root, and when they handle a request, they run as someone else.  When
it's done, they're root again, hanging out waiting on another request.

If there's significant interest, I can clean up my code a little bit (we're talking
about ~10 lines) and post it here.

Note that I've only tested this with HTTP/1.0 IP-based virtual-hosting.  I don't see
any reason why it wouldn't work with the 1.1 stuff, but since I only use IP hosting,
I haven't tested it.

In a situation such as this, does anyone think any aspect of Apache could be
broken?   Perhaps I'm overlooking something?  Are there any additional security
concerns to watch out for?  If it looks like a good idea, why isn't there already a
patch for it?  :)

-Steve

Interpath Communications, Inc.
Raleigh, North Carolina


Re: C++ reserved words

Posted by John Zedlewski <ze...@Princeton.EDU>.
Personally, I always have my editor set to syntax highlight for C++.
Any variables that use reserved words look funny immediately.
--JRZ

> For people not familiar with C++, you might want to watch out for
> these reserved words if there is any chance your code will be
> converted to C++ (some of these are very unlikely to appear anywhere
> but in a C++ program, but you never know): bad_cast, bad_typeid,
> bool, catch, class, const_cast, delete, dynamic_cast, explicit,
> export, false, friend, inline, mutable, namespace, new, operator,
> private, protected, public, reinterpret_cast, static_cast, template,
> this, throw, true, try, typeid, typename, using, virtual.


Re: Yet another discussion and [PATCH] for ap_sendfile

Posted by Greg Marr <gr...@alum.wpi.edu>.
At 05:09 PM 11/23/99 , you wrote:
>On Mon, 22 Nov 1999, Ryan Bloom wrote:
> >...
> > Oh, I also changed a parameter name.  I am trying VERY hard not 
> to name
> > variables the same name as a C Run-Time function.  That's why all 
> the old
> > ap_socket_t *socket 's have been renamed to ap_socket_t *sock.
>
>You might also want to toss your uses of "new" as a variable name. I 
>think
>I saw that in some of the locking code.
>
>Needless to say, "new" will cause problems with C++ compiles.

When recently porting a 1M+ line program from C to C++, I ran into a 
few other reserved words from C++ that were used heavily: delete, 
class, typeid, this.

For people not familiar with C++, you might want to watch out for 
these reserved words if there is any chance your code will be 
converted to C++ (some of these are very unlikely to appear anywhere 
but in a C++ program, but you never know): bad_cast, bad_typeid, 
bool, catch, class, const_cast, delete, dynamic_cast, explicit, 
export, false, friend, inline, mutable, namespace, new, operator, 
private, protected, public, reinterpret_cast, static_cast, template, 
this, throw, true, try, typeid, typename, using, virtual.

--
Greg Marr
gregm@alum.wpi.edu
"We thought you were dead."
"I was, but I'm better now." - Sheridan, "The Summoning"


Re: Yet another discussion and [PATCH] for ap_sendfile

Posted by Ryan Bloom <rb...@ntrnet.net>.
On Tue, 23 Nov 1999, Greg Stein wrote:

> On Mon, 22 Nov 1999, Ryan Bloom wrote:
> >...
> > Oh, I also changed a parameter name.  I am trying VERY hard not to name
> > variables the same name as a C Run-Time function.  That's why all the old
> > ap_socket_t *socket 's have been renamed to ap_socket_t *sock.
> 
> You might also want to toss your uses of "new" as a variable name. I think
> I saw that in some of the locking code.
> 
> Needless to say, "new" will cause problems with C++ compiles.

I may do that in time.  Currently, we don't compile with C++, so it wasn't
an issue.  I'm not dealing with it for this release of APR.

Ryan

_______________________________________________________________________________
Ryan Bloom                        	rbb@ntrnet.net
6209 H Shanda Dr.
Raleigh, NC 27609		Ryan Bloom -- thinker, adventurer, artist,
				     writer, but mostly, friend.
-------------------------------------------------------------------------------


Re: Yet another discussion and [PATCH] for ap_sendfile

Posted by Greg Stein <gs...@lyra.org>.
On Mon, 22 Nov 1999, Ryan Bloom wrote:
>...
> Oh, I also changed a parameter name.  I am trying VERY hard not to name
> variables the same name as a C Run-Time function.  That's why all the old
> ap_socket_t *socket 's have been renamed to ap_socket_t *sock.

You might also want to toss your uses of "new" as a variable name. I think
I saw that in some of the locking code.

Needless to say, "new" will cause problems with C++ compiles.

Cheers,
-g

-- 
Greg Stein, http://www.lyra.org/


Re: Yet another discussion and [PATCH] for ap_sendfile

Posted by Ryan Bloom <rb...@raleigh.ibm.com>.
> I general, I like this patch.  I am re-posting it, because I have cleaned
> up the formating a bit.  Took out some tabs, and re-generated it against
> the tree from CVS.  I added a few commands to autoconf to get
> HAVE_SENDFILE defined for us.  I also added the APR_HAS_SENDFILE #define.
> It is defined at the same time as HAVE_SENDFILE, but APR_HAS_SENDFILE
> makes sense on platforms like Windows, which doesn't have autoconf.  It is
> an APR feature macro, and I am trying to get those into place now.  :-)

Oh, I also changed a parameter name.  I am trying VERY hard not to name
variables the same name as a C Run-Time function.  That's why all the old
ap_socket_t *socket 's have been renamed to ap_socket_t *sock.

Ryan

_______________________________________________________________________
Ryan Bloom		rbb@raleigh.ibm.com
4205 S Miami Blvd	
RTP, NC 27709		It's a beautiful sight to see good dancers 
			doing simple steps.  It's a painful sight to
			see beginners doing complicated patterns.	


Re: Yet another discussion and [PATCH] for ap_sendfile

Posted by Ryan Bloom <rb...@raleigh.ibm.com>.
> I found it pretty much impossible to come up with a general method for
> obtaining an ap_socket_t struct from a given request_rec.  If you drill
> down through rec->client->iol->fd on Unix, you can turn that into one, but
> I guess the struct request_rec just hasn't been updated to handle APR.
> Perhaps an ap_socket_t will just be added to conn_rec in place of some of
> the fields already there?

This shouldn't be necessary.  What you should do, is put a sendfile
function into the IOL, if APR_HAS_SENDFILE is defined.  Then, we call the
iol's sendfile function, which resolves to ap_sendfile.  If this isn't
obvious from the VERY breif description I gave, let me know.  It isn't
hard, but I am too lazy to go into details.  :-)

I general, I like this patch.  I am re-posting it, because I have cleaned
up the formating a bit.  Took out some tabs, and re-generated it against
the tree from CVS.  I added a few commands to autoconf to get
HAVE_SENDFILE defined for us.  I also added the APR_HAS_SENDFILE #define.
It is defined at the same time as HAVE_SENDFILE, but APR_HAS_SENDFILE
makes sense on platforms like Windows, which doesn't have autoconf.  It is
an APR feature macro, and I am trying to get those into place now.  :-)

If the number of differences between the CVS tree scared you away from
looking into this patch, please review it now.  They are gone.  If nobody
responds to this patch by Turkey Day, I will be committing it either that
day or the day after, depending on if I get a chance to login that day.
:->

Ryan

Index: src/lib/apr/acconfig.h
===================================================================
RCS file: /home/cvs/apache-2.0/src/lib/apr/acconfig.h,v
retrieving revision 1.13
diff -u -r1.13 acconfig.h
--- acconfig.h	1999/11/17 18:09:55	1.13
+++ acconfig.h	1999/11/22 15:19:47
@@ -46,6 +46,7 @@
 
 #undef SIZEOF_SSIZE_T
 #undef APR_HAS_THREADS
+#undef APR_HAS_SENDFILE
 
 @BOTTOM@
 #define API_EXPORT(type) type
Index: src/lib/apr/configure.in
===================================================================
RCS file: /home/cvs/apache-2.0/src/lib/apr/configure.in,v
retrieving revision 1.27
diff -u -r1.27 configure.in
--- configure.in	1999/11/17 18:09:55	1.27
+++ configure.in	1999/11/22 15:19:47
@@ -212,6 +212,7 @@
 AC_CHECK_FUNCS(strcasecmp stricmp poll setsid)
 AC_CHECK_FUNCS(sigaction writev)
 AC_CHECK_FUNCS(getpass)
+AC_CHECK_FUNCS(sendfile, AC_DEFINE(APR_HAS_SENDFILE))
 AC_CHECK_FUNC(_getch)
 
 AC_CHECK_FUNCS(gmtime_r localtime_r)
Index: src/lib/apr/include/apr_network_io.h
===================================================================
RCS file: /home/cvs/apache-2.0/src/lib/apr/include/apr_network_io.h,v
retrieving revision 1.15
diff -u -r1.15 apr_network_io.h
--- apr_network_io.h	1999/10/29 13:36:28	1.15
+++ apr_network_io.h	1999/11/22 15:19:54
@@ -62,6 +62,7 @@
 
 #include "apr_general.h"
 #include "apr_errno.h"
+#include "apr_file_io.h"
 #include <time.h>
 
 #ifdef HAVE_NETINET_IN_H
@@ -108,6 +109,7 @@
 
 typedef struct socket_t     ap_socket_t;
 typedef struct pollfd_t    ap_pollfd_t;
+typedef struct hdtr_t		ap_hdtr_t;
 
 /* function definitions */
 
@@ -128,6 +130,10 @@
 
 ap_status_t ap_send(ap_socket_t *, const char *, ap_ssize_t *);
 ap_status_t ap_sendv(ap_socket_t *sock, const struct iovec *vec, ap_int32_t nvec, ap_int32_t *nbytes);
+#ifdef HAVE_SENDFILE
+ap_status_t ap_sendfile(ap_socket_t *sock, ap_file_t *file, ap_hdtr_t *hdtr, ap_off_t *offset, 
+                         ap_size_t *len, ap_int32_t flags);
+#endif
 ap_status_t ap_recv(ap_socket_t *, char *, ap_ssize_t *);
 
 ap_status_t ap_setsocketopt(ap_socket_t *, ap_int32_t, ap_int32_t);
Index: src/lib/apr/network_io/unix/sendrecv.c
===================================================================
RCS file: /home/cvs/apache-2.0/src/lib/apr/network_io/unix/sendrecv.c,v
retrieving revision 1.5
diff -u -r1.5 sendrecv.c
--- sendrecv.c	1999/11/15 19:49:51	1.5
+++ sendrecv.c	1999/11/22 15:20:05
@@ -60,8 +60,27 @@
 #include "apr_general.h"
 #include "apr_network_io.h"
 #include "apr_lib.h"
+#if HAVE_SYS_TIME_H
 #include <sys/time.h>
+#endif
 
+#ifdef HAVE_SENDFILE
+/* TODO: Not every platform needs all of these includes, some should disappear */
+/* We need to include this to access members of the ap_file_t struct */
+#include "../../file_io/unix/fileio.h"
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <netinet/tcp.h>
+#include <netinet/in.h>
+/* Glibc2.1.1 fails to define TCP_CORK.  This is a bug that will be fixed in the next
+ * release.  It should be 3 */
+#if !defined(TCP_CORK) && defined(__linux__)
+#define TCP_CORK 3
+#endif
+
+#endif /* HAVE_SENDFILE */
+
 /* ***APRDOC********************************************************
  * ap_status_t ap_send(ap_socket_t *, const char *, ap_ssize_t *, time_t)
  *    Send data over a network.
@@ -176,4 +195,371 @@
     (*len) = rv;
     return APR_SUCCESS;
 }
+
+/* ***APRDOC********************************************************
+ * ap_status_t ap_sendv(ap_socket_t *, const struct iovec *, ap_int32_t, ap_int32_t *)
+ *    Send multiple packets of data over a network.
+ * arg 1) The socket to send the data over.
+ * arg 2) The array of iovec structs containing the data to send 
+ * arg 3) The number of iovec structs in the array
+ * arg 4) Receives the number of bytes actually written
+ * NOTE:  This functions acts like a blocking write by default.  To change 
+ *        this behavior, use ap_setsocketopt with the APR_SO_TIMEOUT option.
+ *        The number of bytes actually sent is stored in argument 3.
+ */
+ap_status_t ap_sendv(struct socket_t * sock, const struct iovec * vec,
+                     ap_int32_t nvec, ap_int32_t * nbytes)
+{
+    ssize_t rv;
+
+    do {
+        rv = writev(sock->socketdes, vec, nvec);
+    } while (rv == -1 && errno == EINTR);
+
+    if (rv == -1 && errno == EAGAIN && sock->timeout != 0) {
+        struct timeval *tv;
+        fd_set fdset;
+        int srv;
+
+        do {
+            FD_ZERO(&fdset);
+            FD_SET(sock->socketdes, &fdset);
+            if (sock->timeout < 0) {
+        	tv = NULL;
+            }
+            else {
+        	tv = ap_palloc(sock->cntxt, sizeof(struct timeval));
+        	tv->tv_sec = sock->timeout;
+        	tv->tv_usec = 0;
+            }
+            srv = select(FD_SETSIZE, NULL, &fdset, NULL, tv);
+        } while (srv == -1 && errno == EINTR);
+
+        if (srv == 0) {
+            (*nbytes) = -1;
+            return APR_TIMEUP;
+        }
+        else if (srv < 0) {
+            (*nbytes) = -1;
+            return errno;
+        }
+        else {
+            do {
+        	rv = writev(sock->socketdes, vec, nvec);
+            } while (rv == -1 && errno == EINTR);
+        }
+    }
+    (*nbytes) = rv;
+    return APR_SUCCESS;
+}
+
+#if defined(HAVE_SENDFILE)
+/* ***APRDOC********************************************************
+ * ap_status_t ap_sendfile(ap_socket_t *, ap_file_t *, ap_hdtr_t *, 
+ *                         ap_off_t *, ap_size_t *, ap_int32_t flags)
+ *    Send a file from an open file descriptor to a socket, along with 
+ *    optional headers and trailers
+ * arg 1) The socket to which we're writing
+ * arg 2) The open file from which to read
+ * arg 3) A structure containing the headers and trailers to send
+ * arg 4) Offset into the file where we should begin writing
+ * arg 5) Number of bytes to send 
+ * arg 6) OS-specific flags to pass to sendfile()
+ * NOTE:  This functions acts like a blocking write by default.  To change 
+ *        this behavior, use ap_setsocketopt with the APR_SO_TIMEOUT option.
+ *        The number of bytes actually sent is stored in argument 4.
+ */
+
+ /* TODO: Verify that all platforms handle the fd the same way 
+  *     (i.e. not moving current file pointer)
+  *     - Should flags be an int_32 or what?
+  */
+
+#if defined(__linux__) && defined(HAVE_WRITEV)
+ap_status_t ap_sendfile(ap_socket_t * sock, ap_file_t * file,
+        		ap_hdtr_t * hdtr, ap_off_t * offset, ap_size_t * len,
+        		ap_int32_t flags)
+{
+    off_t off = *offset;
+    int corkflag = 1;
+    int rv, nbytes = 0;
+
+    /* TCP_CORK keeps us from sending partial frames when we shouldn't */
+    rv = setsockopt(socket->socketdes, SOL_TCP, TCP_CORK,
+        	    (const void *) &corkflag, sizeof(corkflag));
+    if (rv == -1) {
+        return errno;
+    }
+
+    /* Now write the headers */
+    if (hdtr->numheaders > 0) {
+        ap_int32_t hdrbytes;
+        rv = ap_sendv(sock, hdtr->headers, hdtr->numheaders, &hdrbytes);
+        if (rv != APR_SUCCESS) {
+            return errno;
+        }
+        nbytes += hdrbytes;
+    }
+
+    do {
+        rv = sendfile(sock->socketdes,	/* socket */
+        	      file->filedes,	/* open file descriptor of the file to be sent */
+        	      &off,	/* where in the file to start */
+        	      *len	/* number of bytes to send */
+            );
+    } while (rv == -1 && errno == EINTR);
+
+    if (rv == -1 && errno == EAGAIN && socket->timeout != 0) {
+        struct timeval *tv;
+        fd_set fdset;
+        int srv;
+        do {
+            FD_ZERO(&fdset);
+            FD_SET(sock->socketdes, &fdset);
+            if (sock->timeout < 0) {
+        	tv = NULL;
+            }
+            else {
+        	tv = ap_palloc(sock->cntxt, sizeof(struct timeval));
+        	tv->tv_sec = sock->timeout;
+        	tv->tv_usec = 0;
+            }
+            srv = select(FD_SETSIZE, NULL, &fdset, NULL, tv);
+        } while (srv == -1 && errno == EINTR);
+
+        if (srv == 0) {
+            (*len) = -1;
+            return APR_TIMEUP;
+        }
+        else if (srv < 0) {
+            (*len) = -1;
+            return errno;
+        }
+        else {
+            do {
+        	rv = sendfile(sock->socketdes,	/* socket */
+        		      file->filedes,	/* open file descriptor of the file to be sent */
+        		      &off,	/* where in the file to start */
+        		      *len);	/* number of bytes to send */
+            } while (rv == -1 && errno == EINTR);
+        }
+    }
+
+    if (rv == -1) {
+        return errno;
+    }
+
+    nbytes += rv;
+
+    /* Now write the footers */
+    if (hdtr->numtrailers > 0) {
+        ap_int32_t trbytes;
+        rv = ap_sendv(socket, hdtr->trailers, hdtr->numtrailers, &trbytes);
+        if (rv == -1) {
+            return errno;
+        }
+        nbytes += trbytes;
+    }
+
+    /* Uncork to send queued frames */
+    corkflag = 0;
+    rv = setsockopt(socket->socketdes, SOL_TCP, TCP_CORK,
+                    (const void *) &corkflag, sizeof(corkflag));
+
+    (*len) = nbytes;
+    return APR_SUCCESS;
+}
+
+/* These are just demos of how the code for the other OSes.
+ * I haven't tested these, but they're right in terms of interface.
+ * I just wanted to see what types of vars would be required from other OSes. 
+ */
+
+#elif defined(__FreeBSD__)
+/* Release 3.1 or greater */
+ap_status_t ap_sendfile(ap_socket_t * sock, ap_file_t * file,
+        		ap_hdtr_t * hdtr, ap_off_t * offset, ap_size_t * len,
+        		ap_int32_t flags)
+{
+    off_t nbytes;
+    int rv;
+    struct sf_hdtr headerstruct;
+
+    headerstruct.headers = hdtr->headers;
+    headerstruct.hdr_cnt = hdtr->numheaders;
+    headerstruct.trailers = hdtr->trailers;
+    headerstruct.trl_cnt = hdtr->numtrailers;
+
+
+    /* FreeBSD can send the headers/footers as part of the system call */
+    do {
+        rv = sendfile(file->filedes,	/* open file descriptor of the file to be sent */
+        	      sock->socketdes,	/* socket */
+        	      *offset,	/* where in the file to start */
+        	      (size_t) * len,	/* number of bytes to send */
+        	      &headerstruct,	/* Headers/footers */
+        	      &nbytes,	/* number of bytes written */
+        	      flags	/* undefined, set to 0 */
+            );
+    } while (rv == -1 && errno == EINTR);
+
+    if (rv == -1 && errno == EAGAIN && sock->timeout != 0) {
+        struct timeval *tv;
+        fd_set fdset;
+        int srv;
+
+        do {
+            FD_ZERO(&fdset);
+            FD_SET(socket->socketdes, &fdset);
+            if (socket->timeout < 0) {
+        	tv = NULL;
+            }
+            else {
+        	tv = ap_palloc(socket->cntxt, sizeof(struct timeval));
+        	tv->tv_sec = sock->timeout;
+        	tv->tv_usec = 0;
+            }
+            srv = select(FD_SETSIZE, NULL, &fdset, NULL, tv);
+        } while (srv == -1 && errno == EINTR);
+
+        if (srv == 0) {
+            (*len) = -1;
+            return APR_TIMEUP;
+        }
+        else if (srv < 0) {
+            (*len) = -1;
+            return errno;
+        }
+        else {
+            do {
+        	rv = sendfile(file->filedes,	/* open file descriptor of the file to be sent */
+        		      sock->socketdes,	/* socket */
+        		      *offset,	/* where in the file to start */
+        		      (size_t) * len,	/* number of bytes to send */
+        		      &headerstruct,	/* Headers/footers */
+        		      &nbytes,	/* number of bytes written */
+        		      flags	/* undefined, set to 0 */
+        	    );
+            } while (rv == -1 && errno == EINTR);
+        }
+    }
+
+
+    if (rv == -1) {
+        return errno;
+    }
+
+    (*len) = nbytes;
+    return APR_SUCCESS;
+}
+
+#elif defined(__HPUX__)
+
+/* HP-UX Version 10.30 or greater */
+ap_status_t ap_sendfile(ap_socket_t * sock, ap_file_t * file,
+        		ap_hdtr_t * hdtr, ap_off_t * offset, ap_size_t * len,
+        		ap_int32_t flags)
+{
+    int i, ptr = 0;
+    size_t nbytes = 0, headerlen = 0, trailerlen = 0;
+    struct sf_hdtr headerstruct;
+    struct iovec hdtrarray[2];
+    void *headerbuf, *trailerbuf;
+
+
+    /* HP-UX can only send one header iovec and one footer iovec */
+
+    for (i = 0; i < hdtr->numheaders; i++) {
+        headerlen += hdtr->headers[i].iov_len;
+    }
+
+    headerbuf = ap_palloc(socket->cntxt, headerlen);
+
+    for (i = 0; i < hdtr->numheaders; i++) {
+        memcpy(headerbuf, hdtr->headers[i].iov_base + ptr,
+               hdtr->headers[i].iov_len);
+        ptr += hdtr->headers[i].iov_len;
+    }
+
+    for (i = 0; i < hdtr->numtrailers; i++) {
+        trailerlen += hdtr->headers[i].iov_len;
+    }
+
+    trailerbuf = ap_palloc(socket->cntxt, trailerlen);
+
+    for (i = 0; i < hdtr->numtrailers; i++) {
+        memcpy(trailerbuf, hdtr->trailers[i].iov_base + ptr,
+               hdtr->trailers[i].iov_len);
+        ptr += hdtr->trailers[i].iov_len;
+    }
+
+    hdtrarray[0].iov_base = headerbuf;
+    hdtrarray[0].iov_len = headerlen;
+    hdtrarray[1].iov_base = trailerbuf;
+    hdtrarray[1].iov_len = trailerlen;
+
+    do {
+        rv = sendfile(sock->socketdes,	/* socket  */
+        	      file->filedes,	/* file descriptor to send */
+        	      *offset,	/* where in the file to start */
+        	      nbytes,	/* number of bytes to send */
+        	      hdtrarray,	/* Headers/footers */
+        	      flags	/* undefined, set to 0 */
+            );
+    } while (rv == -1 && errno == EINTR);
+
+    if (rv == -1 && errno == EAGAIN && sock->timeout != 0) {
+        struct timeval *tv;
+        fd_set fdset;
+        int srv;
+
+        do {
+            FD_ZERO(&fdset);
+            FD_SET(socket->socketdes, &fdset);
+            if (socket->timeout < 0) {
+        	tv = NULL;
+            }
+            else {
+        	tv = ap_palloc(socket->cntxt, sizeof(struct timeval));
+        	tv->tv_sec = sock->timeout;
+        	tv->tv_usec = 0;
+            }
+            srv = select(FD_SETSIZE, NULL, &fdset, NULL, tv);
+        } while (srv == -1 && errno == EINTR);
+
+        if (srv == 0) {
+            (*len) = -1;
+            return APR_TIMEUP;
+        }
+        else if (srv < 0) {
+            (*len) = -1;
+            return errno;
+        }
+        else {
+            do {
+        	rv = sendfile(sock->socketdes,	/* socket  */
+        		      file->filedes,	/* file descriptor to send */
+        		      *offset,	/* where in the file to start */
+        		      nbytes,	/* number of bytes to send */
+        		      hdtrarray,	/* Headers/footers */
+        		      flags	/* undefined, set to 0 */
+        	    );
+            } while (rv == -1 && errno == EINTR);
+        }
+    }
+
+
+    if (rv == -1) {
+        return errno;
+    }
+
+
+    /* Set len to the number of bytes written */
+    (*len) = rv;
+    return APR_SUCCESS;
+}
+#else
+/* TODO: Add AIX support */
+#endif /* __linux__, __FreeBSD__, __HPUX__ */
+#endif /* HAVE_SENDFILE */
 

_______________________________________________________________________
Ryan Bloom		rbb@raleigh.ibm.com
4205 S Miami Blvd	
RTP, NC 27709		It's a beautiful sight to see good dancers 
			doing simple steps.  It's a painful sight to
			see beginners doing complicated patterns.	


Yet another discussion and [PATCH] for ap_sendfile

Posted by John Zedlewski <ze...@Princeton.EDU>.
Ok, finally I have a patch that actually does everything it should,
including the possibilities of EINTR and EAGAIN returns for sendfile.
I've included the apr_network_io.h patch (for the function def and hdtr_t,
a structure for headers and trailers) and the
apr/network_io/unix/sendrecv.c patch.  I also had to implement ap_sendv
for use with Linux.

Issues/questions:
    I didn't send in the http_core patch necessary to put this function to
use, though it's pretty much done.  It needs a new ap_get_http_header
function, which is pretty easy.  More importantly and generally, however,
I found it pretty much impossible to come up with a general method for
obtaining an ap_socket_t struct from a given request_rec.  If you drill
down through rec->client->iol->fd on Unix, you can turn that into one, but
I guess the struct request_rec just hasn't been updated to handle APR.
Perhaps an ap_socket_t will just be added to conn_rec in place of some of
the fields already there?
    This version is written to send an arbitrary number of headers and
footers.  This is the general form that was suggested earlier on this
list.  However, only FreeBSD natively supports and arbitrary number of
headers and footers.  Win32, AIX, and HP-UX each support one header and
one footer, while Linux supports none in the sendfile system call.  We
could simplify matters noticeably by only allowing a single header and
footer in ap_sendfile.  Can anyone think of cases where sending more than
one would be very useful?

Other comments:
    I included ap_sendfile functions for HP-UX and FreeBSD which are
generally correct according to the docs for those OSes.  I don't have
access to machines with either, though, so these are non-debugged roadmaps
for someone else to follow.  I didn't even touch AIX, but its API is
basically a cross between FreeBSD's and HP-UX's, and I can do it later if
the current stuff seems all right.
    Sorry there's some extraneous crap in the patch.  I ran it through GNU
indent to get formatting right, and it seems to differ a little bit from
the indenting of the old sendrecv.c.  Just skip down to ap_sendv and
ap_sendfile.
    I have a Win32 version almost done, but I want to get some feedback on
these first.

Thanks!
--JRZ


Re: Setuid Apache?

Posted by Marc Slemko <ma...@znep.com>.
On Mon, 15 Nov 1999, Stephen Andrew Misel wrote:

>The processes wait for connections as root, and once a connection
>has been made, it calls setegid() and seteuid() for the User and
>Group specified in the conf file for that VirtualHost.  If the
>request is a non CGI (or SSI, etc) the request is handled and that
>process does a setegid() and seteuid() back to root to wait for
>the next request.

>In the event we're dealing with a CGI and need to fork(), the
>setegid() and seteuid() are back to root, at which point it calls
>setgid() and setuid() to assume the user's real identity (verses
>effective), and then forks off the child.  Of course, when the
>request is complete, it assumes root again and waits in the free
>pool.

 
>I see the security implications here as minimal, as long as the
>server makes a confirmation that it's uid/gid change was successful
>before serving documents or running CGI's (otherwise they'd run as
>root, bad bad).  Am I correct?

No.  Running the server in that manner means that any bug in the server 
(eg. buffer overflow) will allow a root compromise.  That is not a 
very good thing and, because of that, I'm doubtful that such code has
a place in the Apache distribution.  

Sure, it is convenient.  But it is also quite risky.