base64_decode() with heimdal libs, so I've renamed it base64_decode_inplace().
[ira/wip.git] / source3 / web / cgi.c
index 3739d712d3981d82712000b6bdeaf713491ddee7..8abc2f0bd5c6b5ff20b6b1972d92c92eacd6a7fd 100644 (file)
@@ -1,6 +1,6 @@
 /* 
    some simple CGI helper routines
-   Copyright (C) Andrew Tridgell 1997
+   Copyright (C) Andrew Tridgell 1997-1998
    
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
 */
 
 
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/stat.h>
-#include <string.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <pwd.h>
+#include "includes.h"
+#include "../web/swat_proto.h"
 
 #define MAX_VARIABLES 10000
 
+/* set the expiry on fixed pages */
+#define EXPIRY_TIME (60*60*24*7)
+
 #ifdef DEBUG_COMMENTS
 extern void print_title(char *fmt, ...);
 #endif
@@ -41,58 +39,32 @@ static struct var variables[MAX_VARIABLES];
 static int num_variables;
 static int content_length;
 static int request_post;
-static int request_get;
 static char *query_string;
-
-static void unescape(char *buf)
-{
-       char *p=buf;
-
-       while ((p=strchr(p,'+')))
-               *p = ' ';
-
-       p = buf;
-
-       while (p && *p && (p=strchr(p,'%'))) {
-               int c1 = p[1];
-               int c2 = p[2];
-
-               if (c1 >= '0' && c1 <= '9')
-                       c1 = c1 - '0';
-               else if (c1 >= 'A' && c1 <= 'F')
-                       c1 = 10 + c1 - 'A';
-               else if (c1 >= 'a' && c1 <= 'f')
-                       c1 = 10 + c1 - 'a';
-               else {p++; continue;}
-
-               if (c2 >= '0' && c2 <= '9')
-                       c2 = c2 - '0';
-               else if (c2 >= 'A' && c2 <= 'F')
-                       c2 = 10 + c2 - 'A';
-               else if (c2 >= 'a' && c2 <= 'f')
-                       c2 = 10 + c2 - 'a';
-               else {p++; continue;}
-                       
-               *p = (c1<<4) | c2;
-
-               memcpy(p+1, p+3, strlen(p+3)+1);
-               p++;
-       }
-}
-
+static const char *baseurl;
+static char *pathinfo;
+static char *C_user;
+static BOOL inetd_server;
+static BOOL got_request;
 
 static char *grab_line(FILE *f, int *cl)
 {
-       char *ret;
+       char *ret = NULL;
        int i = 0;
-       int len = 1024;
-
-       ret = (char *)malloc(len);
-       if (!ret) return NULL;
-       
+       int len = 0;
 
        while ((*cl)) {
-               int c = fgetc(f);
+               int c;
+       
+               if (i == len) {
+                       char *ret2;
+                       if (len == 0) len = 1024;
+                       else len *= 2;
+                       ret2 = (char *)Realloc(ret, len);
+                       if (!ret2) return ret;
+                       ret = ret2;
+               }
+       
+               c = fgetc(f);
                (*cl)--;
 
                if (c == EOF) {
@@ -102,17 +74,10 @@ static char *grab_line(FILE *f, int *cl)
                
                if (c == '\r') continue;
 
-               if (strchr("\n&", c)) break;
+               if (strchr_m("\n&", c)) break;
 
                ret[i++] = c;
 
-               if (i == len-1) {
-                       char *ret2;
-                       ret2 = (char *)realloc(ret, len*2);
-                       if (!ret2) return ret;
-                       len *= 2;
-                       ret = ret2;
-               }
        }
        
 
@@ -125,40 +90,33 @@ static char *grab_line(FILE *f, int *cl)
   with the same name and the same or different values. Takes a file parameter
   for simulating CGI invocation eg loading saved preferences.
   ***************************************************************************/
-void cgi_load_variables(FILE *f1)
+void cgi_load_variables(void)
 {
-       FILE *f = f1;
        static char *line;
        char *p, *s, *tok;
-       int len;
+       int len, i;
+       FILE *f = stdin;
 
 #ifdef DEBUG_COMMENTS
        char dummy[100]="";
        print_title(dummy);
-       printf("<!== Start dump in cgi_load_variables() %s ==>\n",__FILE__);
+       d_printf("<!== Start dump in cgi_load_variables() %s ==>\n",__FILE__);
 #endif
 
-       if (!f1) {
-               f = stdin;
-               if (!content_length) {
-                       p = getenv("CONTENT_LENGTH");
-                       len = p?atoi(p):0;
-               } else {
-                       len = content_length;
-               }
+       if (!content_length) {
+               p = getenv("CONTENT_LENGTH");
+               len = p?atoi(p):0;
        } else {
-               fseek(f, 0, SEEK_END);
-               len = ftell(f);
-               fseek(f, 0, SEEK_SET);
+               len = content_length;
        }
 
 
        if (len > 0 && 
-           (f1 || request_post ||
+           (request_post ||
             ((s=getenv("REQUEST_METHOD")) && 
              strcasecmp(s,"POST")==0))) {
                while (len && (line=grab_line(f, &len))) {
-                       p = strchr(line,'=');
+                       p = strchr_m(line,'=');
                        if (!p) continue;
                        
                        *p = 0;
@@ -166,14 +124,14 @@ void cgi_load_variables(FILE *f1)
                        variables[num_variables].name = strdup(line);
                        variables[num_variables].value = strdup(p+1);
 
-                       free(line);
+                       SAFE_FREE(line);
                        
                        if (!variables[num_variables].name || 
                            !variables[num_variables].value)
                                continue;
 
-                       unescape(variables[num_variables].value);
-                       unescape(variables[num_variables].name);
+                       rfc1738_unescape(variables[num_variables].value);
+                       rfc1738_unescape(variables[num_variables].name);
 
 #ifdef DEBUG_COMMENTS
                        printf("<!== POST var %s has value \"%s\"  ==>\n",
@@ -186,18 +144,12 @@ void cgi_load_variables(FILE *f1)
                }
        }
 
-       if (f1) {
-#ifdef DEBUG_COMMENTS
-               printf("<!== End dump in cgi_load_variables() ==>\n"); 
-#endif
-               return;
-       }
-
        fclose(stdin);
+       open("/dev/null", O_RDWR);
 
        if ((s=query_string) || (s=getenv("QUERY_STRING"))) {
                for (tok=strtok(s,"&;");tok;tok=strtok(NULL,"&;")) {
-                       p = strchr(tok,'=');
+                       p = strchr_m(tok,'=');
                        if (!p) continue;
                        
                        *p = 0;
@@ -209,8 +161,8 @@ void cgi_load_variables(FILE *f1)
                            !variables[num_variables].value)
                                continue;
 
-                       unescape(variables[num_variables].value);
-                       unescape(variables[num_variables].name);
+                       rfc1738_unescape(variables[num_variables].value);
+                       rfc1738_unescape(variables[num_variables].name);
 
 #ifdef DEBUG_COMMENTS
                         printf("<!== Commandline var %s has value \"%s\"  ==>\n",
@@ -225,6 +177,24 @@ void cgi_load_variables(FILE *f1)
 #ifdef DEBUG_COMMENTS
         printf("<!== End dump in cgi_load_variables() ==>\n");   
 #endif
+
+       /* variables from the client are in display charset - convert them
+          to our internal charset before use */
+       for (i=0;i<num_variables;i++) {
+               pstring dest;
+
+               convert_string(CH_DISPLAY, CH_UNIX, 
+                              variables[i].name, -1, 
+                              dest, sizeof(dest));
+               free(variables[i].name);
+               variables[i].name = strdup(dest);
+
+               convert_string(CH_DISPLAY, CH_UNIX, 
+                              variables[i].value, -1,
+                              dest, sizeof(dest));
+               free(variables[i].value);
+               variables[i].value = strdup(dest);
+       }
 }
 
 
@@ -235,7 +205,7 @@ void cgi_load_variables(FILE *f1)
   browser. Also doesn't allow for variables[] containing multiple variables
   with the same name and the same or different values.
   ***************************************************************************/
-char *cgi_variable(char *name)
+const char *cgi_variable(const char *name)
 {
        int i;
 
@@ -246,251 +216,167 @@ char *cgi_variable(char *name)
 }
 
 /***************************************************************************
-return a particular cgi variable
-  ***************************************************************************/
-char *cgi_vnum(int i, char **name)
-{
-       if (i < 0 || i >= num_variables) return NULL;
-       *name = variables[i].name;
-       return variables[i].value;
-}
-
-/***************************************************************************
-  return the value of a CGI boolean variable.
-  ***************************************************************************/
-int cgi_boolean(char *name, int def)
-{
-       char *p = cgi_variable(name);
-
-       if (!p) return def;
-
-       return strcmp(p, "1") == 0;
-}
-
-/***************************************************************************
-like strdup() but quotes < > and &
+tell a browser about a fatal error in the http processing
   ***************************************************************************/
-char *quotedup(char *s)
+static void cgi_setup_error(const char *err, const char *header, const char *info)
 {
-       int i, n=0;
-       int len;
-       char *ret;
-       char *d;
-
-       if (!s) return strdup("");
-
-       len = strlen(s);
-
-       for (i=0;i<len;i++)
-               if (s[i] == '<' || s[i] == '>' || s[i] == '&')
-                       n++;
-
-       ret = malloc(len + n*6 + 1);
-
-       if (!ret) return NULL;
-
-       d = ret;
-
-       for (i=0;i<len;i++) {
-               switch (s[i]) {
-               case '<':
-                       strcpy(d, "&lt;");
-                       d += 4;
-                       break;
-
-               case '>':
-                       strcpy(d, "&gt;");
-                       d += 4;
-                       break;
-
-               case '&':
-                       strcpy(d, "&amp;");
-                       d += 5;
-                       break;
-
-               default:
-                       *d++ = s[i];
+       if (!got_request) {
+               /* damn browsers don't like getting cut off before they give a request */
+               char line[1024];
+               while (fgets(line, sizeof(line)-1, stdin)) {
+                       if (strncasecmp(line,"GET ", 4)==0 || 
+                           strncasecmp(line,"POST ", 5)==0 ||
+                           strncasecmp(line,"PUT ", 4)==0) {
+                               break;
+                       }
                }
        }
 
-       *d = 0;
-
-       return ret;
+       d_printf("HTTP/1.0 %s\r\n%sConnection: close\r\nContent-Type: text/html\r\n\r\n<HTML><HEAD><TITLE>%s</TITLE></HEAD><BODY><H1>%s</H1>%s<p></BODY></HTML>\r\n\r\n", err, header, err, err, info);
+       fclose(stdin);
+       fclose(stdout);
+       exit(0);
 }
 
 
 /***************************************************************************
-like strdup() but quotes a wide range of characters
+tell a browser about a fatal authentication error
   ***************************************************************************/
-char *urlquote(char *s)
+static void cgi_auth_error(void)
 {
-       int i, n=0;
-       int len;
-       char *ret;
-       char *d;
-       char *qlist = "\"\n\r'&<> \t+;";
-
-       if (!s) return strdup("");
-
-       len = strlen(s);
-
-       for (i=0;i<len;i++)
-               if (strchr(qlist, s[i])) n++;
-
-       ret = malloc(len + n*2 + 1);
-
-       if (!ret) return NULL;
-
-       d = ret;
+       if (inetd_server) {
+                cgi_setup_error("401 Authorization Required", 
+                                "WWW-Authenticate: Basic realm=\"SWAT\"\r\n",
+                                "You must be authenticated to use this service");
+       } else {
+               printf("Content-Type: text/html\r\n");
 
-       for (i=0;i<len;i++) {
-               if (strchr(qlist,s[i])) {
-                       sprintf(d, "%%%02X", (int)s[i]);
-                       d += 3;
-               } else {
-                       *d++ = s[i];
-               }
+               printf("\r\n<HTML><HEAD><TITLE>SWAT</TITLE></HEAD>\n");
+               printf("<BODY><H1>Installation Error</H1>\n");
+               printf("SWAT must be installed via inetd. It cannot be run as a CGI script<p>\n");
+               printf("</BODY></HTML>\r\n");
        }
-
-       *d = 0;
-
-       return ret;
+       exit(0);
 }
 
-
 /***************************************************************************
-like strdup() but quotes " characters
+authenticate when we are running as a CGI
   ***************************************************************************/
-char *quotequotes(char *s)
+static void cgi_web_auth(void)
 {
-       int i, n=0;
-       int len;
-       char *ret;
-       char *d;
-
-       if (!s) return strdup("");
-
-       len = strlen(s);
-
-       for (i=0;i<len;i++)
-               if (s[i] == '"')
-                       n++;
-
-       ret = malloc(len + n*6 + 1);
-
-       if (!ret) return NULL;
-
-       d = ret;
-
-       for (i=0;i<len;i++) {
-               switch (s[i]) {
-               case '"':
-                       strcpy(d, "&quot;");
-                       d += 6;
-                       break;
+       const char *user = getenv("REMOTE_USER");
+       struct passwd *pwd;
+       const char *head = "Content-Type: text/html\r\n\r\n<HTML><BODY><H1>SWAT installation Error</H1>\n";
+       const char *tail = "</BODY></HTML>\r\n";
 
-               default:
-                       *d++ = s[i];
-               }
+       if (!user) {
+               printf("%sREMOTE_USER not set. Not authenticated by web server.<br>%s\n",
+                      head, tail);
+               exit(0);
        }
 
-       *d = 0;
-
-       return ret;
-}
-
-
-/***************************************************************************
-quote spaces in a buffer
-  ***************************************************************************/
-void quote_spaces(char *buf)
-{
-       while (*buf) {
-               if (*buf == ' ') *buf = '+';
-               buf++;
+       pwd = getpwnam_alloc(user);
+       if (!pwd) {
+               printf("%sCannot find user %s<br>%s\n", head, user, tail);
+               exit(0);
        }
-}
-
 
-
-/***************************************************************************
-tell a browser about a fatal error in the http processing
-  ***************************************************************************/
-static void cgi_setup_error(char *err, char *header, char *info)
-{
-       printf("HTTP/1.1 %s\r\n%sConnection: close\r\nContent-Type: text/html\r\n\r\n<HTML><HEAD><TITLE>%s</TITLE></HEAD><BODY><H1>%s</H1>%s<p></BODY></HTML>\r\n", err, header, err, err, info);
-       exit(0);
-}
-
-
-/***************************************************************************
-decode a base64 string in-place - simple and slow algorithm
-  ***************************************************************************/
-static void base64_decode(char *s)
-{
-       char *b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
-       int bit_offset, byte_offset, idx, i;
-       unsigned char *d = (unsigned char *)s;
-       char *p;
-
-       i=0;
-
-       while (*s && (p=strchr(b64,*s))) {
-               idx = (int)(p - b64);
-               byte_offset = (i*6)/8;
-               bit_offset = (i*6)%8;
-               d[byte_offset] &= ~((1<<(8-bit_offset))-1);
-               if (bit_offset < 3) {
-                       d[byte_offset] |= (idx << (2-bit_offset));
-               } else {
-                       d[byte_offset] |= (idx >> (bit_offset-2));
-                       d[byte_offset+1] = 0;
-                       d[byte_offset+1] |= (idx << (8-(bit_offset-2))) & 0xFF;
-               }
-               s++; i++;
+       setuid(0);
+       setuid(pwd->pw_uid);
+       if (geteuid() != pwd->pw_uid || getuid() != pwd->pw_uid) {
+               printf("%sFailed to become user %s - uid=%d/%d<br>%s\n", 
+                      head, user, (int)geteuid(), (int)getuid(), tail);
+               exit(0);
        }
+       passwd_free(&pwd);
 }
 
 
 /***************************************************************************
 handle a http authentication line
   ***************************************************************************/
-static int cgi_handle_authorization(char *line)
+static BOOL cgi_handle_authorization(char *line)
 {
-       char *p, *user, *pass;
-       struct passwd *pwd;
-       int ret=0;
+       char *p;
+       fstring user, user_pass;
+       struct passwd *pass = NULL;
 
        if (strncasecmp(line,"Basic ", 6)) {
-               cgi_setup_error("401 Bad Authorization", "", 
-                               "Only basic authorization is understood");
+               goto err;
        }
        line += 6;
        while (line[0] == ' ') line++;
-       base64_decode(line);
-       if (!(p=strchr(line,':'))) {
-               cgi_setup_error("401 Bad Authorization", "", 
-                               "username/password must be supplied");
+       base64_decode_inplace(line);
+       if (!(p=strchr_m(line,':'))) {
+               /*
+                * Always give the same error so a cracker
+                * cannot tell why we fail.
+                */
+               goto err;
        }
        *p = 0;
-       user = line;
-       pass = p+1;
 
-       /* currently only allow connections as root */
-       if (strcasecmp(user,"root")) {
-               cgi_setup_error("401 Bad Authorization", "", 
-                               "incorrect username/password");
+       convert_string(CH_DISPLAY, CH_UNIX, 
+                      line, -1, 
+                      user, sizeof(user));
+
+       convert_string(CH_DISPLAY, CH_UNIX, 
+                      p+1, -1, 
+                      user_pass, sizeof(user_pass));
+
+       /*
+        * Try and get the user from the UNIX password file.
+        */
+       
+       pass = getpwnam_alloc(user);
+       
+       /*
+        * Validate the password they have given.
+        */
+       
+       if NT_STATUS_IS_OK(pass_check(pass, user, user_pass, 
+                     strlen(user_pass), NULL, False)) {
+               
+               if (pass) {
+                       /*
+                        * Password was ok.
+                        */
+                       
+                       become_user_permanently(pass->pw_uid, pass->pw_gid);
+                       
+                       /* Save the users name */
+                       C_user = strdup(user);
+                       passwd_free(&pass);
+                       return True;
+               }
        }
        
-       pwd = getpwnam(user);
+err:
+       cgi_setup_error("401 Bad Authorization", "", 
+                       "username or password incorrect");
 
-       if (!strcmp((char *)crypt(pass, pwd->pw_passwd),pwd->pw_passwd)) {
-               ret = 1;
-       }
+       passwd_free(&pass);
+       return False;
+}
 
-       memset(pass, 0, strlen(pass));
+/***************************************************************************
+is this root?
+  ***************************************************************************/
+BOOL am_root(void)
+{
+       if (geteuid() == 0) {
+               return( True);
+       } else {
+               return( False);
+       }
+}
 
-       return ret;
+/***************************************************************************
+return a ptr to the users name
+  ***************************************************************************/
+char *cgi_user_name(void)
+{
+        return(C_user);
 }
 
 
@@ -499,28 +385,49 @@ handle a file download
   ***************************************************************************/
 static void cgi_download(char *file)
 {
-       struct stat st;
+       SMB_STRUCT_STAT st;
        char buf[1024];
-       int fd, l;
+       int fd, l, i;
        char *p;
+       char *lang;
+
+       /* sanitise the filename */
+       for (i=0;file[i];i++) {
+               if (!isalnum((int)file[i]) && !strchr_m("/.-_", file[i])) {
+                       cgi_setup_error("404 File Not Found","",
+                                       "Illegal character in filename");
+               }
+       }
 
        if (!file_exist(file, &st)) {
                cgi_setup_error("404 File Not Found","",
                                "The requested file was not found");
        }
-       fd = open(file,O_RDONLY);
+
+       fd = web_open(file,O_RDONLY,0);
        if (fd == -1) {
                cgi_setup_error("404 File Not Found","",
                                "The requested file was not found");
        }
-       printf("HTTP/1.1 200 OK\r\n");
-       if ((p=strrchr(file,'.'))) {
-               if (strcmp(p,".gif")==0 || strcmp(p,".jpg")==0) {
+       printf("HTTP/1.0 200 OK\r\n");
+       if ((p=strrchr_m(file,'.'))) {
+               if (strcmp(p,".gif")==0) {
                        printf("Content-Type: image/gif\r\n");
+               } else if (strcmp(p,".jpg")==0) {
+                       printf("Content-Type: image/jpeg\r\n");
+               } else if (strcmp(p,".txt")==0) {
+                       printf("Content-Type: text/plain\r\n");
                } else {
                        printf("Content-Type: text/html\r\n");
                }
        }
+       printf("Expires: %s\r\n", http_timestring(time(NULL)+EXPIRY_TIME));
+
+       lang = lang_tdb_current();
+       if (lang) {
+               printf("Content-Language: %s\r\n", lang);
+       }
+
        printf("Content-Length: %d\r\n\r\n", (int)st.st_size);
        while ((l=read(fd,buf,sizeof(buf)))>0) {
                fwrite(buf, 1, l, stdout);
@@ -530,52 +437,78 @@ static void cgi_download(char *file)
 }
 
 
-/***************************************************************************
-setup the cgi framework, handling the possability that this program is either
-run as a true cgi program by a web browser or is itself a mini web server
-  ***************************************************************************/
-void cgi_setup(char *rootdir)
+
+
+/**
+ * @brief Setup the CGI framework.
+ *
+ * Setup the cgi framework, handling the possibility that this program
+ * is either run as a true CGI program with a gateway to a web server, or
+ * is itself a mini web server.
+ **/
+void cgi_setup(const char *rootdir, int auth_required)
 {
-       int authenticated = 0;
+       BOOL authenticated = False;
        char line[1024];
        char *url=NULL;
        char *p;
+       char *lang;
 
        if (chdir(rootdir)) {
                cgi_setup_error("400 Server Error", "",
                                "chdir failed - the server is not configured correctly");
        }
 
+       /* Handle the possability we might be running as non-root */
+       sec_init();
+
+       if ((lang=getenv("HTTP_ACCEPT_LANGUAGE"))) {
+               /* if running as a cgi program */
+               web_set_lang(lang);
+       }
+
+       /* maybe we are running under a web server */
        if (getenv("CONTENT_LENGTH") || getenv("REQUEST_METHOD")) {
-               /* assume we are running under a real web server */
+               if (auth_required) {
+                       cgi_web_auth();
+               }
                return;
        }
 
+       inetd_server = True;
+
+       if (!check_access(1, lp_hostsallow(-1), lp_hostsdeny(-1))) {
+               cgi_setup_error("400 Server Error", "",
+                               "Samba is configured to deny access from this client\n<br>Check your \"hosts allow\" and \"hosts deny\" options in smb.conf ");
+       }
+
        /* we are a mini-web server. We need to read the request from stdin
           and handle authentication etc */
        while (fgets(line, sizeof(line)-1, stdin)) {
                if (line[0] == '\r' || line[0] == '\n') break;
                if (strncasecmp(line,"GET ", 4)==0) {
-                       request_get = 1;
+                       got_request = True;
                        url = strdup(&line[4]);
                } else if (strncasecmp(line,"POST ", 5)==0) {
+                       got_request = True;
                        request_post = 1;
                        url = strdup(&line[5]);
                } else if (strncasecmp(line,"PUT ", 4)==0) {
+                       got_request = True;
                        cgi_setup_error("400 Bad Request", "",
                                        "This server does not accept PUT requests");
                } else if (strncasecmp(line,"Authorization: ", 15)==0) {
                        authenticated = cgi_handle_authorization(&line[15]);
                } else if (strncasecmp(line,"Content-Length: ", 16)==0) {
                        content_length = atoi(&line[16]);
+               } else if (strncasecmp(line,"Accept-Language: ", 17)==0) {
+                       web_set_lang(&line[17]);
                }
                /* ignore all other requests! */
        }
 
-       if (!authenticated) {
-               cgi_setup_error("401 Authorization Required", 
-                               "WWW-Authenticate: Basic realm=\"samba\"\r\n",
-                               "You must be authenticated to use this service");
+       if (auth_required && !authenticated) {
+               cgi_auth_error();
        }
 
        if (!url) {
@@ -584,23 +517,88 @@ void cgi_setup(char *rootdir)
        }
 
        /* trim the URL */
-       if ((p = strchr(url,' ')) || (p=strchr(url,'\t'))) {
+       if ((p = strchr_m(url,' ')) || (p=strchr_m(url,'\t'))) {
                *p = 0;
        }
-       while (*url && strchr("\r\n",url[strlen(url)-1])) {
+       while (*url && strchr_m("\r\n",url[strlen(url)-1])) {
                url[strlen(url)-1] = 0;
        }
 
        /* anything following a ? in the URL is part of the query string */
-       if ((p=strchr(url,'?'))) {
+       if ((p=strchr_m(url,'?'))) {
                query_string = p+1;
                *p = 0;
        }
 
-       if (strcmp(url,"/")) {
-               cgi_download(url+1);
+       string_sub(url, "/swat/", "", 0);
+
+       if (url[0] != '/' && strstr(url,"..")==0 && file_exist(url, NULL)) {
+               cgi_download(url);
        }
 
-       printf("HTTP/1.1 200 OK\r\nConnection: close\r\nContent-Type: text/html\r\n\r\n");
-       
+       printf("HTTP/1.0 200 OK\r\nConnection: close\r\n");
+       printf("Date: %s\r\n", http_timestring(time(NULL)));
+       baseurl = "";
+       pathinfo = url+1;
+}
+
+
+/***************************************************************************
+return the current pages URL
+  ***************************************************************************/
+const char *cgi_baseurl(void)
+{
+       if (inetd_server) {
+               return baseurl;
+       }
+       return getenv("SCRIPT_NAME");
+}
+
+/***************************************************************************
+return the current pages path info
+  ***************************************************************************/
+const char *cgi_pathinfo(void)
+{
+       char *r;
+       if (inetd_server) {
+               return pathinfo;
+       }
+       r = getenv("PATH_INFO");
+       if (!r) return "";
+       if (*r == '/') r++;
+       return r;
+}
+
+/***************************************************************************
+return the hostname of the client
+  ***************************************************************************/
+char *cgi_remote_host(void)
+{
+       if (inetd_server) {
+               return get_socket_name(1,False);
+       }
+       return getenv("REMOTE_HOST");
+}
+
+/***************************************************************************
+return the hostname of the client
+  ***************************************************************************/
+char *cgi_remote_addr(void)
+{
+       if (inetd_server) {
+               return get_socket_addr(1);
+       }
+       return getenv("REMOTE_ADDR");
+}
+
+
+/***************************************************************************
+return True if the request was a POST
+  ***************************************************************************/
+BOOL cgi_waspost(void)
+{
+       if (inetd_server) {
+               return request_post;
+       }
+       return strequal(getenv("REQUEST_METHOD"), "POST");
 }