summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--TO_FIX.md14
-rw-r--r--config.toml.sample15
-rwxr-xr-xgmi.pl164
3 files changed, 121 insertions, 72 deletions
diff --git a/TO_FIX.md b/TO_FIX.md
index e3a2b3e..1c95988 100644
--- a/TO_FIX.md
+++ b/TO_FIX.md
@@ -2,10 +2,18 @@ TODO:
can log_file be written to?
add systemd unit?
-root_relative parameter is not needed, should be able to tell if a path is relative or not by the first character.
gmi.pl needs to accept an arguemnt, where the config.toml is located.
-default's root is relative to working_dir which is bad behavior.
-
remove magic numbers
redirection bug where path = /share/dir, redirection says '30 share/dir/' resulting in '/share/share/dir/'
+
+in dir_listing, if a file has white space, then it will not properly display.
+server does not do anything with '%20' (whitespace) in path at all.
+
+Be able to listen on more ports and different ip addresses -- make vhost adjustable.
+
+make log output user adjustable
+
+add client certificate stuff
+
+add gmiaccess stuff
diff --git a/config.toml.sample b/config.toml.sample
index 5cd6c63..3552ae3 100644
--- a/config.toml.sample
+++ b/config.toml.sample
@@ -17,6 +17,10 @@ log_to_stdout = true
# Unless path is absolute, it is relative to working_dir.
# If this is not specified then it will place it in certs dir (and create the directory if needed, maybe not with the best permissions)
cert_key_dir = "certs" # avoid putting final '/'
+# If the cert_key_dir directory is not writable, then a warning will emit
+# because generating cert/key pairs will fail and cause the program to die.
+# Setting the following to 'false' will not emit an error.
+cert_key_dir_write_warning = true
## These are not specific to default and can be used with vhost
## Vhost options will override default options
@@ -24,7 +28,7 @@ cert_key_dir = "certs" # avoid putting final '/'
root = "default_root"
# append 'index.gmi' when the path ends with '/' or is nothing
assume_index = true
-# list the contents of a directory if no index.gmi is found and request is a directory?
+# list the contents of a directory if no index.gmi is found and request is a directory
dir_listing = false
# otherwise the fallback is 'application/octet-stream' (gemini is primary text based so 'octet-stream' probably not wanted)
default_mime = 'text/plain'
@@ -37,11 +41,11 @@ default_mime = 'text/plain'
# No need for a single config file
#include_configs = ["./sites_enabled"]
+# A Vhost is *required* since it both serves as vhost and server name identification (sni)
# Vhost example - probably you want to see that it actually works right away
['localhost']
# Generate certificate and key automatically? Uses cert_key_dir
auto_cert = true
-
# Overrides default setting
assume_index = true
@@ -49,15 +53,14 @@ assume_index = true
#['example.com']
#auto_cert = false
# Location to the cert/key pair is relative to cert_key_dir unless the path is absolute
-# The existance of cert or key option will cause auto_cert to be ignored.
+# The existance of cert and key option will cause auto_cert to be ignored.
#cert = "cert.pem" # a file
#key = "key.pem" # a file
-
+#
# this Vhost's document root
#root = "/srv/gemini/example.com"
+#
# Overrides default setting
-#root_relative = false
-
#assume_index = true
#dir_listing = true
#default_mime = 'text/plain'
diff --git a/gmi.pl b/gmi.pl
index f8d97c9..2ccb072 100755
--- a/gmi.pl
+++ b/gmi.pl
@@ -7,7 +7,7 @@ use warnings;
use 5.010;
#use diagnostics;
-our $VERSION = 'v0.0.3b';
+our $VERSION = 'v0.0.4';
# Modules
use IO::Socket::SSL; # CPAN
@@ -49,10 +49,10 @@ our %GEM_RES_CODES = (
);
our @VALID_DEFAULT_SETTINGS =
- qw/bind ports tls assume_index dir_listing root root_relative working_dir cert_key_dir
- log_file log_to_stdout default_mime/;
+ qw/bind ports tls assume_index dir_listing root working_dir cert_key_dir
+ log_file log_to_stdout default_mime cert_key_dir_write_warning/;
our @VALID_VHOST_SETTINGS =
- qw/auto_cert assume_index dir_listing root root_relative cert key default_mime/;
+ qw/auto_cert assume_index dir_listing root cert key default_mime/;
my $ft = File::Type->new();
@@ -139,26 +139,38 @@ else {
my $cert_key_dir;
if (exists $config->{default}{cert_key_dir}) {
+ my $p = abs_or_rel($config->{default}{cert_key_dir});
# Absolute
- if (substr($config->{default}{cert_key_dir},0,1) eq '/') {
+ if ($p eq 'abs') {
$cert_key_dir = $config->{default}{cert_key_dir};
}
# Relative
- else {
+ elsif ($p eq 'rel') {
$cert_key_dir = "$working_dir/$config->{default}{cert_key_dir}";
}
+ else {
+ die "cert_key_dir: neither absolute or relative.";
+ }
}
else {
$cert_key_dir = "$working_dir/certs";
}
# Create $cert_key_dir if needed
-if (-d $cert_key_dir and -r $cert_key_dir and -w $cert_key_dir and -x $cert_key_dir) {
- ;
+if (-d $cert_key_dir and -r $cert_key_dir and -x $cert_key_dir) {
+ if (! -w $cert_key_dir) {
+ if (! (exists $config->{default}{cert_key_dir_write_warning}
+ and $config->{default}{cert_key_dir_write_warning} eq 'false'))
+ {
+ say STDERR "cert_key_dir ($cert_key_dir) not writable, generating cert/key pair will cause crash.\n".
+ "(cert_key_dir_write_warning = 'false' to hide this warning.)";
+ }
+ }
} elsif (! -e $cert_key_dir) {
- mkdir $cert_key_dir;
+ mkdir $cert_key_dir
+ or die "Could not create cert_key_dir ($cert_key_dir) - $!";
} else {
- die "cert_key_dir option ($cert_key_dir) is not all of these: ".
- "directory, readable, writable or executeable.";
+ die "cert_key_dir ($cert_key_dir) is not all of these: ".
+ "directory, readable, or executeable.";
}
# Logging
@@ -177,80 +189,89 @@ $| = 1; # Making the *current* Filehandle 'hot' so Perl flushes the buffer immed
my $log;
# VirtualHosts
-for my $item (keys %{ $config }) {
- next if ($item eq 'default');
+for my $vhost (keys %{ $config }) {
+ next if ($vhost eq 'default');
my $error_free = 1;
my $cert_loc;
my $key_loc;
- if (exists $config->{$item}{cert} and exists $config->{$item}{key}) {
+ if (exists $config->{$vhost}{cert} and exists $config->{$vhost}{key}) {
- # checking if absolute location
- if (substr($config->{$item}{cert},0,1) eq '/') {
- if (-e $config->{$item}{cert}) {
- $cert_loc = $config->{$item}{cert};
+ my $p_c = abs_or_rel($config->{$vhost}{cert});
+ if ($p_c eq 'abs') {
+ if (-e $config->{$vhost}{cert}) {
+ $cert_loc = $config->{$vhost}{cert};
}
else {
- say "'$config->{$item}{cert}' does not exist.";
+ say STDERR "'$config->{$vhost}{cert}' for '$vhost' does not exist.";
$error_free = 0;
}
}
- if (substr($config->{$item}{key},0,1) eq '/') {
- if (-e $config->{$item}{key}) {
- $key_loc = $config->{$item}{key};
- }
+ elsif ($p_c eq 'rel') {
+ if (-e "$cert_key_dir/$config->{$vhost}{cert}") {
+ $cert_loc = "$cert_key_dir/$config->{$vhost}{cert}";
+ }
else {
- say "'$config->{$item}{key}' does not exist.";
+ say STDERR "'$cert_key_dir/$config->{$vhost}{cert}' does not exist.";
$error_free = 0;
}
}
+ else {
+ warn "'$config->{$vhost}{cert}' for '$vhost' cert option is neither absolute or relative.";
+ $error_free = 0;
+ }
- # Is it relative?
- if (! $cert_loc or ! $key_loc) {
- if (-e "$cert_key_dir/$config->{$item}{cert}") {
- $cert_loc = "$cert_key_dir/$config->{$item}{cert}";
- }
+ my $p_k = abs_or_rel($config->{$vhost}{key});
+ if ($p_k eq 'abs') {
+ if (-e $config->{$vhost}{key}) {
+ $key_loc = $config->{$vhost}{key};
+ }
else {
- say STDERR "'$cert_key_dir/$config->{$item}{cert}' does not exist.";
+ say STDERR "'$config->{$vhost}{key}' does not exist.";
$error_free = 0;
}
-
- if (-e "$cert_key_dir/$config->{$item}{key}") {
- $key_loc = "$cert_key_dir/$config->{$item}{key}";
+ }
+ elsif ($p_k eq 'rel') {
+ if (-e "$cert_key_dir/$config->{$vhost}{key}") {
+ $key_loc = "$cert_key_dir/$config->{$vhost}{key}";
}
else {
- say STDERR "'$cert_key_dir/$config->{$item}{key}' does not exist.";
+ say STDERR "'$cert_key_dir/$config->{$vhost}{key}' does not exist.";
$error_free = 0;
}
}
+ else {
+ warn "'$config->{$vhost}{key}' for '$vhost' key option is neither absolute or relative.";
+ $error_free = 0;
+ }
}
else {
- if (exists $config->{$item}{auto_cert} and $config->{$item}{auto_cert} ne 'false') {
+ if (exists $config->{$vhost}{auto_cert} and $config->{$vhost}{auto_cert} eq 'true') {
# manage cert for user
- $cert_loc = "$cert_key_dir/$item". '_cert.pem';
- $key_loc = "$cert_key_dir/$item". '_key.pem';
+ $cert_loc = "$cert_key_dir/$vhost". '_cert.pem';
+ $key_loc = "$cert_key_dir/$vhost". '_key.pem';
if (! -e $cert_loc or ! -e $key_loc) {
- say $out "$item cert/key pair generated in '$cert_key_dir'.";
- gen_cert($item, $cert_key_dir)
+ gen_cert($vhost, $cert_key_dir);
+ say $out "$vhost cert/key pair generated in '$cert_key_dir'.";
}
else {
# TODO: make sure cert is valid, otherwise re-generate them
}
}
else {
- say STDERR "$item only has one part of a cert/key pair and/or auto_cert is not enabled.";
+ say STDERR "$vhost only has one part of a cert/key pair and/or auto_cert is not true.";
$error_free = 0;
}
}
if ($error_free) {
- $ssl_config{SSL_cert_file}{$item} = $cert_loc;
- $ssl_config{SSL_key_file}{$item} = $key_loc;
+ $ssl_config{SSL_cert_file}{$vhost} = $cert_loc;
+ $ssl_config{SSL_key_file}{$vhost} = $key_loc;
}
else {
- say STDERR "Will not use cert/key for $item";
+ say STDERR "$vhost: Will will not be listening for incoming requests.";
}
}
@@ -532,30 +553,40 @@ sub get_request_in_vhost_root {
}
### $r
- # relative to working_dir
- if (exists $config->{$vhost}{root} and exists $config->{$vhost}{root_relative} and
- $config->{$vhost}{root_relative} eq 'true')
- {
- my $work_loc = "$working_dir/$config->{$vhost}{root}";
- is_exists_and_readable("$work_loc/$r") ? return "$work_loc/$r" : return undef;
- }
-
- # not relative to working_dir
- elsif (exists $config->{$vhost}{root} and (not exists $config->{$vhost}{root_relative} or
- $config->{$vhost}{root_relative} eq 'false'))
- {
- my $work_loc = "$config->{$vhost}{root}";
- is_exists_and_readable("$work_loc/$r") ? return "$work_loc/$r" : return undef;
+ if (exists $config->{$vhost}{root}) {
+ my $p = abs_or_rel($config->{$vhost}{root});
+ if ($p eq 'abs') {
+ is_exists_and_readable("$config->{$vhost}{root}/$r")
+ ? return "$config->{$vhost}{root}/$r" : return undef;
+ }
+ elsif ($p eq 'rel') {
+ is_exists_and_readable("$working_dir/$config->{$vhost}{root}/$r")
+ ? return "$working_dir/$config->{$vhost}{root}/$r" : return undef;
+ }
+ else {
+ return undef;
+ }
}
-
- # use default's root
- elsif (not exists $config->{$vhost}{root}) {
- my $work_loc = "$working_dir/$config->{default}{root}";
- is_exists_and_readable("$work_loc/$r") ? return "$work_loc/$r" : return undef;
+
+ # try default's root
+ elsif (not exists $config->{$vhost}{root} and exists $config->{default}{root}) {
+ my $p = abs_or_rel($config->{default}{root});
+ if ($p eq 'abs') {
+ is_exists_and_readable("$config->{default}{root}/$r")
+ ? return "$config->{default}{root}/$r" : return undef;
+ }
+ elsif ($p eq 'rel') {
+ is_exists_and_readable("$working_dir/$config->{default}{root}/$r")
+ ? return "$working_dir/$config->{default}{root}/$r" : return undef;
+ }
+ else {
+ say $out "$vhost does not have a valid root and neither does default.";
+ return undef;
+ }
}
else {
- warn "$vhost has improper root/root_relative settings.";
+ say STDERR "default has improper root settings.";
return 0;
}
}
@@ -675,3 +706,10 @@ sub check_vhost_settings {
}
}
+
+sub abs_or_rel {
+ my ($p) = @_;
+ return undef unless (defined $p);
+
+ substr($p,0,1) eq '/' ? return 'abs' : return 'rel';
+}