~sircmpwn/gmnisrv

9f2481dcdf60387e57cfe357bc8d04997c967e57 — dece 2 years ago d7bd3c6
Support REMOTE_USER in CGI
2 files changed, 20 insertions(+), 1 deletions(-)

M doc/gmnisrvini.scd
M src/serve.c
M doc/gmnisrvini.scd => doc/gmnisrvini.scd +3 -0
@@ 184,6 184,9 @@ The following environment variables will be set:
|  *TLS_CLIENT_SERIAL_NUMBER*
:  717823108622037499122666796829184010024179612962
:  Serial number (decimal) of the client certificate.
|  *REMOTE_USER*
:  gemini user
:  Subject common name of the client certificate.

\[1]: gemini://example.org/cgi-bin/foo.sh/bar?hello=world


M src/serve.c => src/serve.c +17 -1
@@ 200,7 200,7 @@ serve_cgi(struct gmnisrv_client *client, const char *path,

		// barebones client cert implementation
		// adapted from openssl(1)'s implementation
		// TODO: support REMOTE_USER, TLS_CLIENT_NOT_{BEFORE,AFTER}
		// TODO: support TLS_CLIENT_NOT_{BEFORE,AFTER}
		X509 *client_cert = SSL_get_peer_certificate(client->ssl);
		if (client_cert != NULL) {
			// 32 bytes because we're always using SHA256, but


@@ 239,8 239,24 @@ serve_cgi(struct gmnisrv_client *client, const char *path,
				const char *error = "Invalid certificate serial number";
				client_submit_response(client,
						GEMINI_STATUS_CERTIFICATE_NOT_VALID, error, NULL);
				goto post_client_cert_parsing;
			}

			X509_NAME* subject_name = X509_get_subject_name(client_cert);
			int cn_index = X509_NAME_get_index_by_NID(subject_name,
					NID_commonName, -1);
			if (cn_index != -1) {
				ASN1_STRING *cn_asn = X509_NAME_ENTRY_get_data(
						X509_NAME_get_entry(subject_name, cn_index));
				unsigned char *cn = malloc(ASN1_STRING_length(cn_asn));
				ASN1_STRING_to_UTF8(&cn, cn_asn);
				setenv("REMOTE_USER", (char*) cn, 1);
				OPENSSL_free(cn);
			} else {
				setenv("REMOTE_USER", "", 1);
			}
		}
		post_client_cert_parsing:

		execlp(path, path, NULL);
		server_error("execlp: %s", strerror(errno));