minor change to panic code
[minix.git] / commands / httpd / police.c
blobb71af8374460474cd38b09fb47cb98e3ab746dd1
1 /* police.c
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>
9 */
10 #include <sys/types.h>
11 #include <sys/stat.h>
12 #include <ctype.h>
13 #include <stdio.h>
14 #include <string.h>
15 #include <stdlib.h>
16 #include <time.h>
17 #include <fcntl.h>
18 #include <unistd.h>
19 #include <errno.h>
21 #include "http.h"
22 #include "utility.h"
23 #include "config.h"
24 #include "pass.h"
26 #define MATCH_NONE 0
27 #define MATCH_WILD 1
28 #define MATCH_FULL 2
30 _PROTOTYPE(static int authaccess, (struct http_request *rq, struct http_reply *rp));
31 _PROTOTYPE(static void purl, (struct http_request *rq, struct http_reply *rp));
32 _PROTOTYPE(static char *virt, (char *to, char *host));
34 static int authaccess(rq, rp)
35 struct http_request *rq;
36 struct http_reply *rp;
38 struct auth *auth;
39 struct authuser *pu;
41 /* set authorization to be checked against */
42 if(rq->type == HTTP_REQUEST_TYPE_PROXY)
43 auth = proxyauth;
44 else
45 auth = rp->auth;
47 /* no authorization so no access to anyone */
48 if(auth == NULL) {
49 rp->status = HTTP_STATUS_FORBIDDEN;
50 strcpy(rp->statusmsg, "No Authoriation");
51 return(-1);
54 /* access must be R for PROXY */
55 if(rq->type == HTTP_REQUEST_TYPE_PROXY)
56 if(!(auth->urlaccess & URLA_READ)) {
57 rp->status = HTTP_STATUS_FORBIDDEN;
58 strcpy(rp->statusmsg, "Proxy not authorized");
59 return(-1);
62 /* no password file so it is a free for all */
63 if(auth->passwdfile == NULL)
64 return(0);
66 /* they did not give us an authorized user */
67 if(rq->authuser[0] == '\0') {
68 if(rq->type == HTTP_REQUEST_TYPE_PROXY)
69 rp->status = HTTP_STATUS_PROXY_AUTH_REQRD;
70 else
71 rp->status = HTTP_STATUS_UNAUTHORIZED;
72 strcpy(rp->statusmsg, "No Authorized User Given");
73 return(-1);
76 /* check if user okay */
77 pu = auth->users;
78 if(pu == NULL)
79 ; /* no user list we allow anyone in file */
80 else {
81 while(pu != NULL) {
82 if(!strcmp(pu->user, rq->authuser))
83 break;
84 pu = pu->next;
86 /* user is not in list so no access */
87 if(pu == NULL) {
88 if(rq->type == HTTP_REQUEST_TYPE_PROXY)
89 rp->status = HTTP_STATUS_PROXY_AUTH_REQRD;
90 else
91 rp->status = HTTP_STATUS_UNAUTHORIZED;
92 strcpy(rp->statusmsg, "Forbidden User not authorized");
93 return(-1);
97 /* check if password file exists, if not no access */
98 if(passfile(auth->passwdfile)) {
99 rp->status = HTTP_STATUS_FORBIDDEN;
100 strcpy(rp->statusmsg, "Invalid passwd file");
101 return(-1);
104 /* check if user in password file, if not no access */
105 if(passuser(auth->passwdfile, rq->authuser)) {
106 if(rq->type == HTTP_REQUEST_TYPE_PROXY)
107 rp->status = HTTP_STATUS_PROXY_AUTH_REQRD;
108 else
109 rp->status = HTTP_STATUS_UNAUTHORIZED;
110 strcpy(rp->statusmsg, "Forbidden Bad User");
111 return(-1);
114 /* check if a password exists, if not no access */
115 if(passnone(auth->passwdfile, rq->authuser)) {
116 if(rq->type == HTTP_REQUEST_TYPE_PROXY)
117 rp->status = HTTP_STATUS_PROXY_AUTH_REQRD;
118 else
119 rp->status = HTTP_STATUS_UNAUTHORIZED;
120 strcpy(rp->statusmsg, "Forbidden no password");
121 return(-1);
124 /* check if password matches, if not no access */
125 if(passpass(auth->passwdfile, rq->authuser, rq->authpass)) {
126 if(rq->type == HTTP_REQUEST_TYPE_PROXY)
127 rp->status = HTTP_STATUS_PROXY_AUTH_REQRD;
128 else
129 rp->status = HTTP_STATUS_UNAUTHORIZED;
130 strcpy(rp->statusmsg, "Forbidden bad password");
131 return(-1);
134 /* whew, all the checks passed so I guess we let them have it */
135 return(0);
138 int police(rq, rp)
139 struct http_request *rq;
140 struct http_reply *rp;
142 int size;
143 struct stat st;
144 struct dirsend *ds;
146 purl(rq, rp);
148 rp->mtype = "text/html";
150 #ifdef DEBUG
151 fprintf(stderr, "httpd: Trying %s\n", rp->realurl);
152 #endif
154 /* now check authorizations */
155 if(authaccess(rq, rp)) {
156 /* Don't give them any details why authorization failed */
157 strcpy(rp->statusmsg, "No Access Granted");
158 return(0);
161 /* a proxy request only needs an authorization check */
162 if(rq->type == HTTP_REQUEST_TYPE_PROXY)
163 return(0);
165 /* check access to real url */
166 if(stat(rp->realurl, &st)) {
167 if(errno == EACCES)
168 rp->status = HTTP_STATUS_FORBIDDEN;
169 else
170 rp->status = HTTP_STATUS_NOT_FOUND;
171 strcpy(rp->statusmsg, strerror(errno));
172 /* a PUT and NOT FOUND is okay since we are creating */
173 if(rq->method != HTTP_METHOD_PUT || rp->status != HTTP_STATUS_NOT_FOUND)
174 return(0);
177 /* If it is a directory do the appropriate thang! */
178 if(rq->method == HTTP_METHOD_GET || rq->method == HTTP_METHOD_HEAD)
179 if((st.st_mode & S_IFMT) == S_IFDIR) {
180 if(rq->url[strlen(rq->url) - 1] != '/') {
181 strncat(rq->url, "/", sizeof(rq->url) - strlen(rq->url));
182 rp->status = HTTP_STATUS_MOVED_TEMP;
183 sprintf(rp->statusmsg, "Moved to %s", rq->url);
184 return(0);
186 size = strlen(rq->url);
187 ds = dirsend;
188 while(ds != NULL) {
189 strncpy(rq->url+size, ds->file, sizeof(rq->url)-size);
190 purl(rq, rp);
191 if(stat(rp->realurl, &st)) {
192 if(errno == EACCES)
193 rp->status = HTTP_STATUS_FORBIDDEN;
194 else
195 if(errno != ENOENT)
196 rp->status = HTTP_STATUS_NOT_FOUND;
197 } else
198 break;
199 if(rp->status != HTTP_STATUS_OK) {
200 strcpy(rp->statusmsg, strerror(errno));
201 return(0);
203 ds = ds->next;
205 if(ds == NULL) {
206 rq->url[size] = '\0';
207 purl(rq, rp);
208 if(stat(rp->realurl, &st)) {
209 if(errno == EACCES)
210 rp->status = HTTP_STATUS_FORBIDDEN;
211 else
212 rp->status = HTTP_STATUS_NOT_FOUND;
213 strcpy(rp->statusmsg, strerror(errno));
214 return(0);
219 if(rq->method == HTTP_METHOD_PUT && !(rp->urlaccess & URLA_WRITE)) {
220 rp->status = HTTP_STATUS_METHOD_NOT_ALLOWED;
221 strcpy(rp->statusmsg, "Method not allowed");
222 return(0);
225 if(rp->status == HTTP_STATUS_OK) {
226 /* Here is where we check if it is a program or script to run */
227 if(cgiexec(rq, rp))
228 return(0);
230 if((st.st_mode & S_IFMT) == S_IFDIR) {
231 rp->status = HTTP_STATUS_NOT_FOUND;
232 strcpy(rp->statusmsg, "Directory listing not available");
233 return(0);
236 if((st.st_mode & S_IFMT) != S_IFREG) {
237 rp->status = HTTP_STATUS_NOT_FOUND;
238 strcpy(rp->statusmsg, "Not a regular file");
239 return(0);
243 /* open the URL for updating */
244 if(rq->method == HTTP_METHOD_PUT) {
245 rp->status = HTTP_STATUS_OK;
246 strcpy(rp->statusmsg, "OK");
247 rp->ofd = open(rp->realurl, O_WRONLY | O_CREAT | O_TRUNC);
248 if(rp->ofd < 0) {
249 if(errno == EACCES)
250 rp->status = HTTP_STATUS_FORBIDDEN;
251 else
252 rp->status = HTTP_STATUS_NOT_FOUND;
253 strcpy(rp->statusmsg, strerror(errno));
254 return(0);
256 return(0);
259 if(!(rp->urlaccess & URLA_READ)) {
260 rp->status = HTTP_STATUS_FORBIDDEN;
261 strcpy(rp->statusmsg, "No way...");
262 return(0);
265 rp->mtype = mimetype(rp->realurl);
267 rp->size = st.st_size;
268 rp->modtime = st.st_mtime;
270 /* open the url if it is a file */
271 rp->fd = open(rp->realurl, O_RDONLY);
272 if(rp->fd < 0) {
273 if(errno == EACCES)
274 rp->status = HTTP_STATUS_FORBIDDEN;
275 else
276 rp->status = HTTP_STATUS_NOT_FOUND;
277 strcpy(rp->statusmsg, strerror(errno));
278 return(0);
281 return(0);
284 static void purl(rq, rp)
285 struct http_request *rq;
286 struct http_reply *rp;
288 struct vpath *pv;
289 int gotreal, gotperm;
290 char *p;
291 int match;
292 int len;
294 gotreal = 0; gotperm = 0;
296 #ifdef DEBUG
297 fprintf(stderr, "httpd: Processing url = \"%s\"\n", rq->url);
298 #endif
300 /* remove any .. references */
301 p = rq->url;
302 while(*p) {
303 while(*p && *p != '/') p++;
304 if(*p != '/') continue;
305 p++;
306 if(*p != '.') continue;
307 p++;
308 if(*p != '.') continue;
309 p++;
310 strcpy(p - 3, p);
311 p = p - 3;
314 for(pv = vpath; pv != NULL; pv = pv->next) {
315 len = strlen(pv->from) - 1;
316 if(pv->from[len] == '*' || pv->from[len] == '$')
317 if(len == 0)
318 match = MATCH_WILD;
319 else
320 match = strncmp(rq->url, pv->from, len) ? MATCH_NONE : MATCH_WILD;
321 else
322 if(!strcmp(rq->url, pv->from))
323 match = MATCH_FULL;
324 else
325 match = MATCH_NONE;
326 #ifdef DEBUG
327 fprintf(stderr, "httpd: Trying \"%s\" %d %d %d %s\n",
328 pv->from, match, gotreal, gotperm, pv->auth->name);
329 #endif
330 if(match != MATCH_NONE) {
331 gotperm = 1;
332 rp->auth = pv->auth;
333 if(pv->urlaccess == -1 && rp->auth != NULL)
334 rp->urlaccess = rp->auth->urlaccess;
335 else
336 rp->urlaccess = pv->urlaccess;
337 if(strcmp(pv->to, ".")) {
338 gotreal = 1;
339 strncpy(rp->realurl, virt(pv->to, rq->host), sizeof(rp->realurl));
340 rp->realurl[sizeof(rp->realurl)-1] = '\0';
341 if(match == MATCH_WILD && pv->from[len] != '$') {
342 strncat(rp->realurl, rq->url+len, sizeof(rp->realurl) - strlen(rp->realurl));
343 rp->realurl[sizeof(rp->realurl)-1] = '\0';
347 if(match == MATCH_FULL) break;
350 if(rp->urlaccess == -1) rp->urlaccess = mkurlaccess("");
352 if(!gotreal) {
353 strncpy(rp->realurl, rq->url, sizeof(rp->realurl));
354 rp->realurl[sizeof(rp->realurl)-1] = '\0';
357 if(!gotperm)
358 rp->auth = NULL;
360 #ifdef DEBUG
361 fprintf(stderr, "DEBUG: url = \"%s\" realurl = \"%s\" auth = \"%s\"\n",
362 rq->url, rp->realurl, ((rp->auth == NULL) ? "No Access" : rp->auth->name));
363 fprintf(stderr, "DEBUG: query = %s\n", rq->query);
364 #endif
366 return;
369 static char *virt(to, host)
370 char *to;
371 char *host;
373 static char vroot[256];
374 struct vhost *ph;
376 #ifdef DEBUG
377 fprintf(stderr, "virt: %s %s\n", to, host);
378 #endif
380 if(vhost == NULL) return(to);
382 if(to[0] != '/') return(to);
383 if(to[1] != '/') return(to);
384 if(to[2] != '/') return(to);
386 vroot[0] = '\0';
388 for(ph = vhost; ph != NULL; ph = ph->next) {
389 #ifdef DEBUG
390 fprintf(stderr, "ph: %s %s %s\n", ph->hname, ph->root, vroot);
391 #endif
392 if(!strcmp(ph->hname, "*") && vroot[0] == '\0')
393 strncpy(vroot, ph->root, sizeof(vroot));
394 if(!strcasecmp(ph->hname, host)) {
395 strncpy(vroot, ph->root, sizeof(vroot));
396 break;
400 strncat(vroot, to+3, sizeof(vroot));
402 #ifdef DEBUG
403 fprintf(stderr, "vroot: %s\n", vroot);
404 #endif
406 return(vroot);