Commit Diff


commit - c603f1260de9fb2cc81dd886a5ddb8e43caa9d0c
commit + 677afbd3f873425bcc6f9a23be7efe3066aed70a
blob - a82bd4f6ff8fb55c88165308a35dc104b9a0bec3
blob + 91d9da971685ea3909deb27798254c548e2353a6
--- README.md
+++ README.md
@@ -127,6 +127,10 @@ with these additional variables set:
 
 > The remote IP address.
 
+`REMOTE_ADDR`
+
+> The remote IP address.
+
 `DOCUMENT_ROOT`
 
 > The root directory being served, the one provided with the
@@ -134,6 +138,23 @@ with these additional variables set:
 > parameter to
 > **gmid**
 
+`AUTH_TYPE`
+
+> The string "Certificate" if the client used a certificate, otherwise unset.
+
+`REMOTE_USER`
+
+> The subject of the client certificate if provided, otherwise unset.
+
+`TLS_CLIENT_ISSUER`
+
+> The is the issuer of the client certificate if provided, otherwise unset.
+
+`TLS_CLIENT_HASH`
+
+> The hash of the client certificate if provided, otherwise unset.
+> The format is "ALGO:HASH".
+
 Let's say you have a script in
 */cgi-bin/script*
 and the user request is
blob - 1a8de5bbdc2bc2bbfa8625092f33ae2fa77ab1d1
blob + 069deea7d7fdb0a25c8c72d27b2f91d6ad79f113
--- gmid.1
+++ gmid.1
@@ -110,11 +110,22 @@ The request relative to the script.
 The query parameters.
 .It Ev REMOTE_HOST
 The remote IP address.
+.It Ev REMOTE_ADDR
+The remote IP address.
 .It Ev DOCUMENT_ROOT
 The root directory being served, the one provided with the
 .Ar d
 parameter to
 .Nm
+.It Ev AUTH_TYPE
+The string "Certificate" if the client used a certificate, otherwise unset.
+.It Ev REMOTE_USER
+The subject of the client certificate if provided, otherwise unset.
+.It Ev TLS_CLIENT_ISSUER
+The is the issuer of the client certificate if provided, otherwise unset.
+.It Ev TLS_CLIENT_HASH
+The hash of the client certificate if provided, otherwise unset.
+The format is "ALGO:HASH".
 .El
 .Pp
 Let's say you have a script in
blob - 65dd66e88127e265cebd4c49480a448cf3468ca5
blob + d75f9b3dccebe0281d83e43ac8644639db569e75
--- gmid.c
+++ gmid.c
@@ -56,6 +56,13 @@
 #define MAX_USERS	64
 #endif
 
+#define SAFE_SETENV(var, val) do {		\
+		const char *_tmp = (val);	\
+		if (_tmp == NULL)		\
+			_tmp = "";		\
+		setenv((var), _tmp, 1);		\
+	} while(0)
+
 enum {
 	S_OPEN,
 	S_INITIALIZING,
@@ -502,18 +509,26 @@ start_cgi(const char *spath, const char *relpath, cons
 		argv[0] = argv[1] = ex;
 
 		/* fix the env */
-		setenv("SERVER_SOFTWARE", "gmid", 1);
-		setenv("SERVER_PORT", portno, 1);
+		SAFE_SETENV("GATEWAY_INTERFACE", "CGI/1.1");
+		SAFE_SETENV("SERVER_SOFTWARE", "gmid");
+		SAFE_SETENV("SERVER_PORT", portno);
 		/* setenv("SERVER_NAME", "", 1); */
-		setenv("SCRIPT_NAME", spath, 1);
-		setenv("SCRIPT_EXECUTABLE", ex, 1);
-		setenv("REQUEST_URI", requri, 1);
-		setenv("REQUEST_RELATIVE", relpath, 1);
-		if (query != NULL)
-			setenv("QUERY_STRING", query, 1);
-		setenv("REMOTE_HOST", addr, 1);
-		setenv("DOCUMENT_ROOT", dir, 1);
+		SAFE_SETENV("SCRIPT_NAME", spath);
+		SAFE_SETENV("SCRIPT_EXECUTABLE", ex);
+		SAFE_SETENV("REQUEST_URI", requri);
+		SAFE_SETENV("REQUEST_RELATIVE", relpath);
+		SAFE_SETENV("QUERY_STRING", query);
+		SAFE_SETENV("REMOTE_HOST", addr);
+		SAFE_SETENV("REMOTE_ADDR", addr);
+		SAFE_SETENV("DOCUMENT_ROOT", dir);
 
+		if (tls_peer_cert_provided(c->ctx)) {
+			SAFE_SETENV("AUTH_TYPE", "Certificate");
+			SAFE_SETENV("REMOTE_USER", tls_peer_cert_subject(c->ctx));
+			SAFE_SETENV("TLS_CLIENT_ISSUER", tls_peer_cert_issuer(c->ctx));
+			SAFE_SETENV("TLS_CLIENT_HASH", tls_peer_cert_hash(c->ctx));
+		}
+
 		execvp(ex, argv);
 		goto childerr;
 	}
@@ -1036,6 +1051,10 @@ main(int argc, char **argv)
 	if ((conf = tls_config_new()) == NULL)
 		err(1, "tls_config_new");
 
+	/* optionally accept client certs, but don't try to verify them */
+	tls_config_verify_client_optional(conf);
+	tls_config_insecure_noverifycert(conf);
+
 	if (tls_config_set_protocols(conf,
 	    TLS_PROTOCOL_TLSv1_2 | TLS_PROTOCOL_TLSv1_3) == -1)
 		err(1, "tls_config_set_protocols");