minix/commands/httpd/police.c
2005-09-16 13:37:29 +00:00

408 lines
9.7 KiB
C

/* police.c
*
* This file is part of httpd.
*
* 02/17/1996 Michael Temari <Michael@TemWare.Com>
* 07/07/1996 Initial Release Michael Temari <Michael@TemWare.Com>
* 12/29/2002 Michael Temari <Michael@TemWare.Com>
*
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include "http.h"
#include "utility.h"
#include "config.h"
#include "pass.h"
#define MATCH_NONE 0
#define MATCH_WILD 1
#define MATCH_FULL 2
_PROTOTYPE(static int authaccess, (struct http_request *rq, struct http_reply *rp));
_PROTOTYPE(static void purl, (struct http_request *rq, struct http_reply *rp));
_PROTOTYPE(static char *virt, (char *to, char *host));
static int authaccess(rq, rp)
struct http_request *rq;
struct http_reply *rp;
{
struct auth *auth;
struct authuser *pu;
/* set authorization to be checked against */
if(rq->type == HTTP_REQUEST_TYPE_PROXY)
auth = proxyauth;
else
auth = rp->auth;
/* no authorization so no access to anyone */
if(auth == NULL) {
rp->status = HTTP_STATUS_FORBIDDEN;
strcpy(rp->statusmsg, "No Authoriation");
return(-1);
}
/* access must be R for PROXY */
if(rq->type == HTTP_REQUEST_TYPE_PROXY)
if(!(auth->urlaccess & URLA_READ)) {
rp->status = HTTP_STATUS_FORBIDDEN;
strcpy(rp->statusmsg, "Proxy not authorized");
return(-1);
}
/* no password file so it is a free for all */
if(auth->passwdfile == NULL)
return(0);
/* they did not give us an authorized user */
if(rq->authuser[0] == '\0') {
if(rq->type == HTTP_REQUEST_TYPE_PROXY)
rp->status = HTTP_STATUS_PROXY_AUTH_REQRD;
else
rp->status = HTTP_STATUS_UNAUTHORIZED;
strcpy(rp->statusmsg, "No Authorized User Given");
return(-1);
}
/* check if user okay */
pu = auth->users;
if(pu == NULL)
; /* no user list we allow anyone in file */
else {
while(pu != NULL) {
if(!strcmp(pu->user, rq->authuser))
break;
pu = pu->next;
}
/* user is not in list so no access */
if(pu == NULL) {
if(rq->type == HTTP_REQUEST_TYPE_PROXY)
rp->status = HTTP_STATUS_PROXY_AUTH_REQRD;
else
rp->status = HTTP_STATUS_UNAUTHORIZED;
strcpy(rp->statusmsg, "Forbidden User not authorized");
return(-1);
}
}
/* check if password file exists, if not no access */
if(passfile(auth->passwdfile)) {
rp->status = HTTP_STATUS_FORBIDDEN;
strcpy(rp->statusmsg, "Invalid passwd file");
return(-1);
}
/* check if user in password file, if not no access */
if(passuser(auth->passwdfile, rq->authuser)) {
if(rq->type == HTTP_REQUEST_TYPE_PROXY)
rp->status = HTTP_STATUS_PROXY_AUTH_REQRD;
else
rp->status = HTTP_STATUS_UNAUTHORIZED;
strcpy(rp->statusmsg, "Forbidden Bad User");
return(-1);
}
/* check if a password exists, if not no access */
if(passnone(auth->passwdfile, rq->authuser)) {
if(rq->type == HTTP_REQUEST_TYPE_PROXY)
rp->status = HTTP_STATUS_PROXY_AUTH_REQRD;
else
rp->status = HTTP_STATUS_UNAUTHORIZED;
strcpy(rp->statusmsg, "Forbidden no password");
return(-1);
}
/* check if password matches, if not no access */
if(passpass(auth->passwdfile, rq->authuser, rq->authpass)) {
if(rq->type == HTTP_REQUEST_TYPE_PROXY)
rp->status = HTTP_STATUS_PROXY_AUTH_REQRD;
else
rp->status = HTTP_STATUS_UNAUTHORIZED;
strcpy(rp->statusmsg, "Forbidden bad password");
return(-1);
}
/* whew, all the checks passed so I guess we let them have it */
return(0);
}
int police(rq, rp)
struct http_request *rq;
struct http_reply *rp;
{
int size;
struct stat st;
struct dirsend *ds;
purl(rq, rp);
rp->mtype = "text/html";
#ifdef DEBUG
fprintf(stderr, "httpd: Trying %s\n", rp->realurl);
#endif
/* now check authorizations */
if(authaccess(rq, rp)) {
/* Don't give them any details why authorization failed */
strcpy(rp->statusmsg, "No Access Granted");
return(0);
}
/* a proxy request only needs an authorization check */
if(rq->type == HTTP_REQUEST_TYPE_PROXY)
return(0);
/* check access to real url */
if(stat(rp->realurl, &st)) {
if(errno == EACCES)
rp->status = HTTP_STATUS_FORBIDDEN;
else
rp->status = HTTP_STATUS_NOT_FOUND;
strcpy(rp->statusmsg, strerror(errno));
/* a PUT and NOT FOUND is okay since we are creating */
if(rq->method != HTTP_METHOD_PUT || rp->status != HTTP_STATUS_NOT_FOUND)
return(0);
}
/* If it is a directory do the appropriate thang! */
if(rq->method == HTTP_METHOD_GET || rq->method == HTTP_METHOD_HEAD)
if((st.st_mode & S_IFMT) == S_IFDIR) {
if(rq->url[strlen(rq->url) - 1] != '/') {
strncat(rq->url, "/", sizeof(rq->url) - strlen(rq->url));
rp->status = HTTP_STATUS_MOVED_TEMP;
sprintf(rp->statusmsg, "Moved to %s", rq->url);
return(0);
}
size = strlen(rq->url);
ds = dirsend;
while(ds != NULL) {
strncpy(rq->url+size, ds->file, sizeof(rq->url)-size);
purl(rq, rp);
if(stat(rp->realurl, &st)) {
if(errno == EACCES)
rp->status = HTTP_STATUS_FORBIDDEN;
else
if(errno != ENOENT)
rp->status = HTTP_STATUS_NOT_FOUND;
} else
break;
if(rp->status != HTTP_STATUS_OK) {
strcpy(rp->statusmsg, strerror(errno));
return(0);
}
ds = ds->next;
}
if(ds == NULL) {
rq->url[size] = '\0';
purl(rq, rp);
if(stat(rp->realurl, &st)) {
if(errno == EACCES)
rp->status = HTTP_STATUS_FORBIDDEN;
else
rp->status = HTTP_STATUS_NOT_FOUND;
strcpy(rp->statusmsg, strerror(errno));
return(0);
}
}
}
if(rq->method == HTTP_METHOD_PUT && !(rp->urlaccess & URLA_WRITE)) {
rp->status = HTTP_STATUS_METHOD_NOT_ALLOWED;
strcpy(rp->statusmsg, "Method not allowed");
return(0);
}
if(rp->status == HTTP_STATUS_OK) {
/* Here is where we check if it is a program or script to run */
if(cgiexec(rq, rp))
return(0);
if((st.st_mode & S_IFMT) == S_IFDIR) {
rp->status = HTTP_STATUS_NOT_FOUND;
strcpy(rp->statusmsg, "Directory listing not available");
return(0);
}
if((st.st_mode & S_IFMT) != S_IFREG) {
rp->status = HTTP_STATUS_NOT_FOUND;
strcpy(rp->statusmsg, "Not a regular file");
return(0);
}
}
/* open the URL for updating */
if(rq->method == HTTP_METHOD_PUT) {
rp->status = HTTP_STATUS_OK;
strcpy(rp->statusmsg, "OK");
rp->ofd = open(rp->realurl, O_WRONLY | O_CREAT | O_TRUNC);
if(rp->ofd < 0) {
if(errno == EACCES)
rp->status = HTTP_STATUS_FORBIDDEN;
else
rp->status = HTTP_STATUS_NOT_FOUND;
strcpy(rp->statusmsg, strerror(errno));
return(0);
}
return(0);
}
if(!(rp->urlaccess & URLA_READ)) {
rp->status = HTTP_STATUS_FORBIDDEN;
strcpy(rp->statusmsg, "No way...");
return(0);
}
rp->mtype = mimetype(rp->realurl);
rp->size = st.st_size;
rp->modtime = st.st_mtime;
/* open the url if it is a file */
rp->fd = open(rp->realurl, O_RDONLY);
if(rp->fd < 0) {
if(errno == EACCES)
rp->status = HTTP_STATUS_FORBIDDEN;
else
rp->status = HTTP_STATUS_NOT_FOUND;
strcpy(rp->statusmsg, strerror(errno));
return(0);
}
return(0);
}
static void purl(rq, rp)
struct http_request *rq;
struct http_reply *rp;
{
struct vpath *pv;
int gotreal, gotperm;
char *p;
int match;
int len;
gotreal = 0; gotperm = 0;
#ifdef DEBUG
fprintf(stderr, "httpd: Processing url = \"%s\"\n", rq->url);
#endif
/* remove any .. references */
p = rq->url;
while(*p) {
while(*p && *p != '/') p++;
if(*p != '/') continue;
p++;
if(*p != '.') continue;
p++;
if(*p != '.') continue;
p++;
strcpy(p - 3, p);
p = p - 3;
}
for(pv = vpath; pv != NULL; pv = pv->next) {
len = strlen(pv->from) - 1;
if(pv->from[len] == '*' || pv->from[len] == '$')
if(len == 0)
match = MATCH_WILD;
else
match = strncmp(rq->url, pv->from, len) ? MATCH_NONE : MATCH_WILD;
else
if(!strcmp(rq->url, pv->from))
match = MATCH_FULL;
else
match = MATCH_NONE;
#ifdef DEBUG
fprintf(stderr, "httpd: Trying \"%s\" %d %d %d %s\n",
pv->from, match, gotreal, gotperm, pv->auth->name);
#endif
if(match != MATCH_NONE) {
gotperm = 1;
rp->auth = pv->auth;
if(pv->urlaccess == -1 && rp->auth != NULL)
rp->urlaccess = rp->auth->urlaccess;
else
rp->urlaccess = pv->urlaccess;
if(strcmp(pv->to, ".")) {
gotreal = 1;
strncpy(rp->realurl, virt(pv->to, rq->host), sizeof(rp->realurl));
rp->realurl[sizeof(rp->realurl)-1] = '\0';
if(match == MATCH_WILD && pv->from[len] != '$') {
strncat(rp->realurl, rq->url+len, sizeof(rp->realurl) - strlen(rp->realurl));
rp->realurl[sizeof(rp->realurl)-1] = '\0';
}
}
}
if(match == MATCH_FULL) break;
}
if(rp->urlaccess == -1) rp->urlaccess = mkurlaccess("");
if(!gotreal) {
strncpy(rp->realurl, rq->url, sizeof(rp->realurl));
rp->realurl[sizeof(rp->realurl)-1] = '\0';
}
if(!gotperm)
rp->auth = NULL;
#ifdef DEBUG
fprintf(stderr, "DEBUG: url = \"%s\" realurl = \"%s\" auth = \"%s\"\n",
rq->url, rp->realurl, ((rp->auth == NULL) ? "No Access" : rp->auth->name));
fprintf(stderr, "DEBUG: query = %s\n", rq->query);
#endif
return;
}
static char *virt(to, host)
char *to;
char *host;
{
static char vroot[256];
struct vhost *ph;
#ifdef DEBUG
fprintf(stderr, "virt: %s %s\n", to, host);
#endif
if(vhost == NULL) return(to);
if(to[0] != '/') return(to);
if(to[1] != '/') return(to);
if(to[2] != '/') return(to);
vroot[0] = '\0';
for(ph = vhost; ph != NULL; ph = ph->next) {
#ifdef DEBUG
fprintf(stderr, "ph: %s %s %s\n", ph->hname, ph->root, vroot);
#endif
if(!strcmp(ph->hname, "*") && vroot[0] == '\0')
strncpy(vroot, ph->root, sizeof(vroot));
if(!strcasecmp(ph->hname, host)) {
strncpy(vroot, ph->root, sizeof(vroot));
break;
}
}
strncat(vroot, to+3, sizeof(vroot));
#ifdef DEBUG
fprintf(stderr, "vroot: %s\n", vroot);
#endif
return(vroot);
}