tImplement some CGI variables for gopher. - geomyidae - A small C-based gopherd. (gopher://bitreich.org/1/scm/geomyidae)
git clone git://r-36.net/geomyidae
Log
Files
Refs
README
LICENSE
---
commit 67eb195e1924b652b193e6332c1ce8f00fd1f2c9
parent f26ccad8ca8d0f79f7195f6871bb2ceac816ccfa
Author: Christoph Lohmann <20h@r-36.net>
Date:   Fri, 26 Jan 2018 13:44:53 +0100

Implement some CGI variables for gopher.

I need this for having a nice IP handler on bitreich.org.

Diffstat:
  handlr.c                            |      20 +++++++++++++-------
  handlr.h                            |      23 ++++++++++++++++++-----
  ind.c                               |      40 +++++++++++++++++++++++++++++++
  ind.h                               |       5 ++++-
  main.c                              |       5 +++--

5 files changed, 78 insertions(+), 15 deletions(-)
---
diff --git a/handlr.c b/handlr.c
t@@ -21,7 +21,7 @@
 
 void
 handledir(int sock, char *path, char *port, char *base, char *args,
-                char *sear, char *ohost)
+                char *sear, char *ohost, char *chost)
 {
         char *pa, *file, *e, *par, *b;
         struct dirent **dirent;
t@@ -78,7 +78,7 @@ handledir(int sock, char *path, char *port, char *base, char *args,
 
 void
 handlegph(int sock, char *file, char *port, char *base, char *args,
-                char *sear, char *ohost)
+                char *sear, char *ohost, char *chost)
 {
         Indexs *act;
         int i, ret = 0;
t@@ -102,7 +102,7 @@ handlegph(int sock, char *file, char *port, char *base, char *args,
 
 void
 handlebin(int sock, char *file, char *port, char *base, char *args,
-                char *sear, char *ohost)
+                char *sear, char *ohost, char *chost)
 {
         int fd;
 
t@@ -122,7 +122,7 @@ handlebin(int sock, char *file, char *port, char *base, char *args,
 
 void
 handlecgi(int sock, char *file, char *port, char *base, char *args,
-                char *sear, char *ohost)
+                char *sear, char *ohost, char *chost)
 {
         char *p, *path;
 
t@@ -157,7 +157,10 @@ handlecgi(int sock, char *file, char *port, char *base, char *args,
                                 break;
                 }
 
-                if (execl(file, p, sear, args, ohost, port, (char *)nil) == -1) {
+                setcgienviron(p, file, port, base, args, sear, ohost, chost);
+
+                if (execl(file, p, sear, args, ohost, port,
+                                (char *)nil) == -1) {
                         perror("execl");
                         _exit(1);
                 }
t@@ -173,7 +176,7 @@ handlecgi(int sock, char *file, char *port, char *base, char *args,
 
 void
 handledcgi(int sock, char *file, char *port, char *base, char *args,
-                char *sear, char *ohost)
+                char *sear, char *ohost, char *chost)
 {
         FILE *fp;
         char *p, *path, *ln = nil;
t@@ -216,7 +219,10 @@ handledcgi(int sock, char *file, char *port, char *base, char *args,
                                 break;
                 }
 
-                if (execl(file, p, sear, args, ohost, port, (char *)nil) == -1) {
+                setcgienviron(p, file, port, base, args, sear, ohost, chost);
+
+                if (execl(file, p, sear, args, ohost, port,
+                                (char *)nil) == -1) {
                         perror("execl");
                         _exit(1);
                 }
diff --git a/handlr.h b/handlr.h
t@@ -6,15 +6,28 @@
 #ifndef HANDLR_H
 #define HANDLR_H
 
+/*
+ * Handler API definition
+ *
+ * path .... path to the script relative from base
+ * port .... port which the script should use when defining menu items
+ *             (See -o and -p in geomyidae(8))
+ * base .... base path of geomyidae ("" in case of chroot)
+ * args .... query string parsed after »script?query«
+ * sear .... search part of request (»selector\tsearch\r\n«)
+ * ohost ... host of geomiydae (See -h in geomyidae(8))
+ * chost ... IP of the client sending a request
+ */
+
 void handledir(int sock, char *path, char *port, char *base, char *args,
-                        char *sear, char *ohost);
+                        char *sear, char *ohost, char *chost);
 void handlegph(int sock, char *file, char *port, char *base, char *args,
-                        char *sear, char *ohost);
+                        char *sear, char *ohost, char *chost);
 void handlebin(int sock, char *file, char *port, char *base, char *args,
-                        char *sear, char *ohost);
+                        char *sear, char *ohost, char *chost);
 void handlecgi(int sock, char *file, char *port, char *base, char *args,
-                        char *sear, char *ohost);
+                        char *sear, char *ohost, char *chost);
 void handledcgi(int sock, char *file, char *port, char *base, char *args,
-                        char *sear, char *ohost);
+                        char *sear, char *ohost, char *chost);
 
 #endif
diff --git a/ind.c b/ind.c
t@@ -419,3 +419,43 @@ reverselookup(char *host)
         return rethost;
 }
 
+void
+setcgienviron(char *file, char *path, char *port, char *base, char *args,
+                char *sear, char *ohost, char *chost)
+{
+        char *s;
+
+        unsetenv("AUTH_TYPE");
+        unsetenv("CONTENT_LENGTH");
+        unsetenv("CONTENT_TYPE");
+        setenv("GATEWAY_INTERFACE", "CGI/1.1", 1);
+        /* TODO: Separate, if run like rest.dcgi. */
+        setenv("PATH_INFO", path, 1);
+
+        s = smprintf("%s/%s", base, path);
+        setenv("PATH_TRANSLATED", s, 1);
+        free(s);
+
+        setenv("QUERY_STRING", args, 1);
+        setenv("REMOTE_ADDR", chost, 1);
+        /*
+         * Don't do a reverse lookup on every call. Only do when needed, in
+         * the script. The RFC allows us to set the IP to the value.
+         */
+        setenv("REMOTE_HOST", chost, 1);
+        unsetenv("REMOTE_IDENT");
+        unsetenv("REMOTE_USER");
+        /*
+         * Only GET is possible in gopher. POST emulation would be really
+         * ugly.
+         */
+        setenv("REQUEST_METHOD", "GET", 1);
+        setenv("SCRIPT_NAME", file, 1);
+        setenv("SERVER_NAME", ohost, 1);
+        setenv("SERVER_PORT", port, 1);
+        setenv("SERVER_PROTOCOL", "gopher/1.0", 1);
+        setenv("SERVER_SOFTWARE", "geomyidae", 1);
+
+        setenv("X_GOPHER_SEARCH", sear, 1);
+}
+
diff --git a/ind.h b/ind.h
t@@ -27,7 +27,8 @@ typedef struct filetype filetype;
 struct filetype {
         char *end;
         char *type;
-        void (* f)(int, char *, char *, char *, char *, char *, char *);
+        void (* f)(int, char *, char *, char *, char *, char *, char *,
+                char *);
 };
 
 filetype *gettype(char *filename);
t@@ -47,6 +48,8 @@ int initlogging(char *logf);
 void stoplogging(int fd);
 char *smprintf(char *fmt, ...);
 char *reverselookup(char *host);
+void setcgienviron(char *file, char *path, char *port, char *base,
+                char *args, char *sear, char *ohost, char *chost);
 
 #endif
 
diff --git a/main.c b/main.c
t@@ -192,10 +192,11 @@ handlerequest(int sock, char *base, char *ohost, char *port, char *clienth,
                 if (c == nil)
                         c = path;
                 type = gettype(c);
-                type->f(sock, path, port, base, args, sear, ohost);
+                type->f(sock, path, port, base, args, sear, ohost, clienth);
         } else {
                 if (S_ISDIR(dir.st_mode)) {
-                        handledir(sock, path, port, base, args, sear, ohost);
+                        handledir(sock, path, port, base, args, sear, ohost,
+                                clienth);
                         if (loglvl & DIRS) {
                                 logentry(clienth, clientp, recvc,
                                                         "dir listing");