improve behaviour under VPC, fixes from nicolas tittley.
[minix.git] / commands / httpd0995 / cgiexec.c
blob856a5120053635526200c539e7c93863689080ba
1 /* cgiexec.c by Michael Temari 02/17/96
3 * This file is part of httpd.
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>
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>
22 #include "http.h"
23 #include "config.h"
24 #include "net.h"
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));
29 int cgiexec(rq, rp)
30 struct http_request *rq;
31 struct http_reply *rp;
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;
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);
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;
61 /* check if prog is allowed to be exec'd */
62 if(!dirflag && !(rp->urlaccess & URLA_EXEC))
63 return(0);
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);
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);
77 argv[0] = prog;
78 argv[1] = rp->realurl;
79 argv[2] = rq->url;
80 argv[3] = (char *)NULL;
82 if(pipe(ifds) < 0) {
83 rp->status = HTTP_STATUS_NOT_FOUND;
84 strcpy(rp->statusmsg, strerror(errno));
85 return(-1);
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);
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);
103 /* We don't know how much data is going to be passed back */
104 rp->size = 0;
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);
113 if(cmdpid != 0) {
114 close(ifds[0]); close(ofds[0]);
115 close(ifds[1]); close(ofds[1]);
116 exit(0);
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);
129 #if 0
130 /* Get rid of Zombie child */
131 (void) wait(&status);
132 #endif
134 close(ifds[1]); close(ofds[0]);
136 rp->fd = ifds[0];
137 rp->ofd = ofds[1];
138 rp->pid = cmdpid;
140 if(rp->urlaccess & URLA_HEADERS)
141 rp->headers = -1;
143 return(-1);
146 char **cgienv(rq, rp)
147 struct http_request *rq;
148 struct http_reply *rp;
150 static char buffer[4096];
151 char *p, *p2;
152 char **e;
153 int len;
154 char temp[20];
156 p = buffer;
157 len = sizeof(buffer);
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);
163 /* HACK - some of these are hardcoded and should not be MAT 3/17/96 */
165 /* HTTP_ */
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);
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);
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);
214 if(len < 1) return(NULL);
215 *p++ = '\0';
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++;
226 if(len < sizeof(e)) return(NULL);
227 *e++ = NULL;
229 return((char **)p);
232 static int addenv(name, value, buf, len)
233 char *name;
234 char *value;
235 char **buf;
236 int *len;
238 char *p;
239 int size;
241 p = *buf;
243 size = strlen(name)+1+strlen(value)+1;
245 if(size > *len)
246 return(-1);
248 sprintf(p, "%s=%s", name, value);
250 p += size;
251 *buf = p;
252 *len -= size;
254 return(0);