[9] | 1 | /* cgiexec.c by Michael Temari 02/17/96
|
---|
| 2 | *
|
---|
| 3 | * This file is part of httpd.
|
---|
| 4 | *
|
---|
| 5 | * 02/17/1996 Michael Temari <Michael@TemWare.Com>
|
---|
| 6 | * 07/07/1996 Initial Release Michael Temari <Michael@TemWare.Com>
|
---|
| 7 | * 12/29/2002 Michael Temari <Michael@TemWare.Com>
|
---|
| 8 | * 02/08/2005 Michael Temari <Michael@TemWare.Com>
|
---|
| 9 | *
|
---|
| 10 | */
|
---|
| 11 | #include <sys/types.h>
|
---|
| 12 | #include <sys/stat.h>
|
---|
| 13 | #include <sys/wait.h>
|
---|
| 14 | #include <stdio.h>
|
---|
| 15 | #include <stdlib.h>
|
---|
| 16 | #include <fcntl.h>
|
---|
| 17 | #include <errno.h>
|
---|
| 18 | #include <unistd.h>
|
---|
| 19 | #include <string.h>
|
---|
| 20 | #include <time.h>
|
---|
| 21 |
|
---|
| 22 | #include "http.h"
|
---|
| 23 | #include "config.h"
|
---|
| 24 | #include "net.h"
|
---|
| 25 |
|
---|
| 26 | _PROTOTYPE(char **cgienv, (struct http_request *rq, struct http_reply *rp));
|
---|
| 27 | _PROTOTYPE(static int addenv, (char *name, char *value, char **buf, int *len));
|
---|
| 28 |
|
---|
| 29 | int cgiexec(rq, rp)
|
---|
| 30 | struct http_request *rq;
|
---|
| 31 | struct http_reply *rp;
|
---|
| 32 | {
|
---|
| 33 | struct stat st;
|
---|
| 34 | char *prog;
|
---|
| 35 | int cmdpid;
|
---|
| 36 | int status;
|
---|
| 37 | char *argv[5];
|
---|
| 38 | int ifds[2];
|
---|
| 39 | int ofds[2];
|
---|
| 40 | static char cmd[2048];
|
---|
| 41 | char **cmdenv;
|
---|
| 42 | int dirflag = 0;
|
---|
| 43 |
|
---|
| 44 | if(stat(rp->realurl, &st)) {
|
---|
| 45 | if(errno == EACCES)
|
---|
| 46 | rp->status = HTTP_STATUS_FORBIDDEN;
|
---|
| 47 | else
|
---|
| 48 | rp->status = HTTP_STATUS_NOT_FOUND;
|
---|
| 49 | strcpy(rp->statusmsg, strerror(errno));
|
---|
| 50 | return(-1);
|
---|
| 51 | }
|
---|
| 52 |
|
---|
| 53 | if((st.st_mode & S_IFMT) == S_IFDIR)
|
---|
| 54 | if(direxec != NULL) {
|
---|
| 55 | prog = direxec; dirflag = 1;
|
---|
| 56 | } else
|
---|
| 57 | return(0);
|
---|
| 58 | else
|
---|
| 59 | prog = rp->realurl;
|
---|
| 60 |
|
---|
| 61 | /* check if prog is allowed to be exec'd */
|
---|
| 62 | if(!dirflag && !(rp->urlaccess & URLA_EXEC))
|
---|
| 63 | return(0);
|
---|
| 64 |
|
---|
| 65 | /* if cannot exec mode then return */
|
---|
| 66 | if( (st.st_mode & S_IXUSR) == 0 &&
|
---|
| 67 | (st.st_mode & S_IXGRP) == 0 &&
|
---|
| 68 | (st.st_mode & S_IXOTH) == 0 )
|
---|
| 69 | return(0);
|
---|
| 70 |
|
---|
| 71 | if((cmdenv = cgienv(rq, rp)) == NULL) {
|
---|
| 72 | rp->status = HTTP_STATUS_SERVER_ERROR;
|
---|
| 73 | strcpy(rp->statusmsg, "Could not setup cgi environment");
|
---|
| 74 | return(-1);
|
---|
| 75 | }
|
---|
| 76 |
|
---|
| 77 | argv[0] = prog;
|
---|
| 78 | argv[1] = rp->realurl;
|
---|
| 79 | argv[2] = rq->url;
|
---|
| 80 | argv[3] = (char *)NULL;
|
---|
| 81 |
|
---|
| 82 | if(pipe(ifds) < 0) {
|
---|
| 83 | rp->status = HTTP_STATUS_NOT_FOUND;
|
---|
| 84 | strcpy(rp->statusmsg, strerror(errno));
|
---|
| 85 | return(-1);
|
---|
| 86 | }
|
---|
| 87 |
|
---|
| 88 | if(pipe(ofds) < 0) {
|
---|
| 89 | rp->status = HTTP_STATUS_NOT_FOUND;
|
---|
| 90 | strcpy(rp->statusmsg, strerror(errno));
|
---|
| 91 | close(ifds[0]); close(ifds[1]);
|
---|
| 92 | return(-1);
|
---|
| 93 | }
|
---|
| 94 |
|
---|
| 95 | if((cmdpid = fork()) < 0) {
|
---|
| 96 | close(ifds[0]); close(ofds[0]);
|
---|
| 97 | close(ifds[1]); close(ofds[1]);
|
---|
| 98 | rp->status = HTTP_STATUS_NOT_FOUND;
|
---|
| 99 | strcpy(rp->statusmsg, strerror(errno));
|
---|
| 100 | return(-1);
|
---|
| 101 | }
|
---|
| 102 |
|
---|
| 103 | /* We don't know how much data is going to be passed back */
|
---|
| 104 | rp->size = 0;
|
---|
| 105 |
|
---|
| 106 | if(cmdpid == 0) { /* Child */
|
---|
| 107 | #if 0
|
---|
| 108 | if((cmdpid = fork()) < 0) {
|
---|
| 109 | close(ifds[0]); close(ofds[0]);
|
---|
| 110 | close(ifds[1]); close(ofds[1]);
|
---|
| 111 | exit(-1);
|
---|
| 112 | }
|
---|
| 113 | if(cmdpid != 0) {
|
---|
| 114 | close(ifds[0]); close(ofds[0]);
|
---|
| 115 | close(ifds[1]); close(ofds[1]);
|
---|
| 116 | exit(0);
|
---|
| 117 | }
|
---|
| 118 | #endif
|
---|
| 119 | setsid();
|
---|
| 120 | close(ifds[0]); close(ofds[1]);
|
---|
| 121 | dup2(ofds[0], 0);
|
---|
| 122 | dup2(ifds[1], 1);
|
---|
| 123 | dup2(ifds[1], 2);
|
---|
| 124 | close(ifds[1]); close(ofds[0]);
|
---|
| 125 | execve(argv[0], argv, cmdenv);
|
---|
| 126 | exit(0);
|
---|
| 127 | }
|
---|
| 128 |
|
---|
| 129 | #if 0
|
---|
| 130 | /* Get rid of Zombie child */
|
---|
| 131 | (void) wait(&status);
|
---|
| 132 | #endif
|
---|
| 133 |
|
---|
| 134 | close(ifds[1]); close(ofds[0]);
|
---|
| 135 |
|
---|
| 136 | rp->fd = ifds[0];
|
---|
| 137 | rp->ofd = ofds[1];
|
---|
| 138 | rp->pid = cmdpid;
|
---|
| 139 |
|
---|
| 140 | if(rp->urlaccess & URLA_HEADERS)
|
---|
| 141 | rp->headers = -1;
|
---|
| 142 |
|
---|
| 143 | return(-1);
|
---|
| 144 | }
|
---|
| 145 |
|
---|
| 146 | char **cgienv(rq, rp)
|
---|
| 147 | struct http_request *rq;
|
---|
| 148 | struct http_reply *rp;
|
---|
| 149 | {
|
---|
| 150 | static char buffer[4096];
|
---|
| 151 | char *p, *p2;
|
---|
| 152 | char **e;
|
---|
| 153 | int len;
|
---|
| 154 | char temp[20];
|
---|
| 155 |
|
---|
| 156 | p = buffer;
|
---|
| 157 | len = sizeof(buffer);
|
---|
| 158 |
|
---|
| 159 | if(addenv("PATH", "/usr/local/bin:/bin:/usr/bin", &p, &len)) return(NULL);
|
---|
| 160 | if(getenv("TZ") != (char *)NULL)
|
---|
| 161 | if(addenv("TZ", getenv("TZ"), &p, &len)) return(NULL);
|
---|
| 162 |
|
---|
| 163 | /* HACK - some of these are hardcoded and should not be MAT 3/17/96 */
|
---|
| 164 |
|
---|
| 165 | /* HTTP_ */
|
---|
| 166 |
|
---|
| 167 | if(addenv("SERVER_SOFTWARE", "Temari httpd/1.0", &p, &len)) return(NULL);
|
---|
| 168 | if(addenv("SERVER_NAME", myhostname, &p, &len)) return(NULL);
|
---|
| 169 | if(addenv("GATEWAY_INTERFACE", "CGI/1.1", &p, &len)) return(NULL);
|
---|
| 170 | if(addenv("SERVER_PROTOCOL", "HTTP/1.0", &p, &len)) return(NULL);
|
---|
| 171 | if(rq->port)
|
---|
| 172 | sprintf(temp, "%u", rq->port);
|
---|
| 173 | else
|
---|
| 174 | strcpy(temp, "80");
|
---|
| 175 | if(addenv("SERVER_PORT", temp, &p, &len)) return(NULL);
|
---|
| 176 | switch(rq->method) {
|
---|
| 177 | case HTTP_METHOD_GET:
|
---|
| 178 | if(addenv("REQUEST_METHOD", "GET", &p, &len)) return(NULL);
|
---|
| 179 | break;
|
---|
| 180 | case HTTP_METHOD_POST:
|
---|
| 181 | if(addenv("REQUEST_METHOD", "POST", &p, &len)) return(NULL);
|
---|
| 182 | break;
|
---|
| 183 | case HTTP_METHOD_HEAD:
|
---|
| 184 | if(addenv("REQUEST_METHOD", "HEAD", &p, &len)) return(NULL);
|
---|
| 185 | break;
|
---|
| 186 | case HTTP_METHOD_PUT:
|
---|
| 187 | if(addenv("REQUEST_METHOD", "PUT", &p, &len)) return(NULL);
|
---|
| 188 | break;
|
---|
| 189 | default:
|
---|
| 190 | if(addenv("REQUEST_METHOD", "UNKNOWN", &p, &len)) return(NULL);
|
---|
| 191 | }
|
---|
| 192 | if(addenv("PATH_INFO", "?", &p, &len)) return(NULL);
|
---|
| 193 | if(addenv("PATH_TRANSLATED", "?", &p, &len)) return(NULL);
|
---|
| 194 | if(addenv("SCRIPT_NAME", rq->url, &p, &len)) return(NULL);
|
---|
| 195 | if(addenv("QUERY_STRING", rq->query, &p, &len)) return(NULL);
|
---|
| 196 | if(addenv("REMOTE_HOST", rmthostname, &p, &len)) return(NULL);
|
---|
| 197 | if(addenv("REMOTE_ADDR", rmthostaddr, &p, &len)) return(NULL);
|
---|
| 198 | if(rq->authuser != (char *)NULL)
|
---|
| 199 | if(addenv("AUTH_USER", rq->authuser, &p, &len)) return(NULL);
|
---|
| 200 | /* AUTH_TYPE */
|
---|
| 201 | /* REMOTE_USER */
|
---|
| 202 | /* REMOTE_IDENT */
|
---|
| 203 | if(rq->method == HTTP_METHOD_POST) {
|
---|
| 204 | if(addenv("CONTENT_TYPE", "application/x-www-form-urlencoded", &p, &len)) return(NULL);
|
---|
| 205 | sprintf(temp, "%lu", rq->size);
|
---|
| 206 | if(addenv("CONTENT_LENGTH", temp, &p, &len)) return(NULL);
|
---|
| 207 | }
|
---|
| 208 | /* COOKIE */
|
---|
| 209 | if(rq->cookie[0] != '\0')
|
---|
| 210 | if(addenv("COOKIE", rq->cookie, &p, &len)) return(NULL);
|
---|
| 211 | /* HOST */
|
---|
| 212 | if(addenv("HOST", rq->host, &p, &len)) return(NULL);
|
---|
| 213 |
|
---|
| 214 | if(len < 1) return(NULL);
|
---|
| 215 | *p++ = '\0';
|
---|
| 216 |
|
---|
| 217 | p2 = buffer;
|
---|
| 218 | e = (char **)p;
|
---|
| 219 | while(*p2) {
|
---|
| 220 | if(len < sizeof(e)) return(NULL);
|
---|
| 221 | len -= sizeof(e);
|
---|
| 222 | *e++ = p2;
|
---|
| 223 | while(*p2) p2++;
|
---|
| 224 | p2++;
|
---|
| 225 | }
|
---|
| 226 | if(len < sizeof(e)) return(NULL);
|
---|
| 227 | *e++ = NULL;
|
---|
| 228 |
|
---|
| 229 | return((char **)p);
|
---|
| 230 | }
|
---|
| 231 |
|
---|
| 232 | static int addenv(name, value, buf, len)
|
---|
| 233 | char *name;
|
---|
| 234 | char *value;
|
---|
| 235 | char **buf;
|
---|
| 236 | int *len;
|
---|
| 237 | {
|
---|
| 238 | char *p;
|
---|
| 239 | int size;
|
---|
| 240 |
|
---|
| 241 | p = *buf;
|
---|
| 242 |
|
---|
| 243 | size = strlen(name)+1+strlen(value)+1;
|
---|
| 244 |
|
---|
| 245 | if(size > *len)
|
---|
| 246 | return(-1);
|
---|
| 247 |
|
---|
| 248 | sprintf(p, "%s=%s", name, value);
|
---|
| 249 |
|
---|
| 250 | p += size;
|
---|
| 251 | *buf = p;
|
---|
| 252 | *len -= size;
|
---|
| 253 |
|
---|
| 254 | return(0);
|
---|
| 255 | }
|
---|