aboutsummaryrefslogtreecommitdiff
path: root/net/stunnel/files
diff options
context:
space:
mode:
authorJeffery To <jeffery.to@gmail.com>2019-01-29 21:21:20 +0800
committerJeffery To <jeffery.to@gmail.com>2019-01-29 21:49:23 +0800
commit8bb3eba3c22f81488f6702ca0c31eeae0441aec0 (patch)
treebc9beb87441617118eddb667461c5a989af49bba /net/stunnel/files
parenteffc8b5bf856d3f1b18be662f6fcb3da1f23566a (diff)
stunnel: Update init script
The reworked init script: * Loads and validates options using uci_validate_section() (through uci_load_validate()) * Allows service options be specified in the globals section * Hard-codes less global options (debug, syslog), as their default values already work * Adds support for almost all options (up to the current package version, 5.49) * Moves the pid file into a subdirectory (/var/run/stunnel) so that it can be created successfully when setuid is used Certain options are omitted: * chroot - requires more setup than the init script can manage * fips, libwrap - disabled at compile-time * iconActive, iconError, iconIdle, taskbar - gui/win32 only * verify - obsolete, verifyChain and/or verifyPeer should be used instead Signed-off-by: Jeffery To <jeffery.to@gmail.com>
Diffstat (limited to 'net/stunnel/files')
-rw-r--r--net/stunnel/files/stunnel.init434
-rw-r--r--net/stunnel/files/stunnel.uci6
2 files changed, 332 insertions, 108 deletions
diff --git a/net/stunnel/files/stunnel.init b/net/stunnel/files/stunnel.init
index a1772e159..0a2dfa416 100644
--- a/net/stunnel/files/stunnel.init
+++ b/net/stunnel/files/stunnel.init
@@ -1,180 +1,402 @@
#!/bin/sh /etc/rc.common
# Copyright (C) 2006-2008 OpenWrt.org
+# Copyright (C) 2019 Jeffery To
START=90
USE_PROCD=1
-PID_FILE="/var/run/stunnel.pid"
-CONF_FILE="/tmp/stunnel.conf"
+PID_FILE="/var/run/stunnel/stunnel.pid"
+CONF_FILE="/var/etc/stunnel.conf"
BIN="/usr/bin/stunnel"
-SERVICE_SECTION_FOUND=0
+CONF_FILE_CREATED=
+HAVE_ALT_CONF_FILE=
+SERVICE_SECTION_FOUND=
-global_defs() {
- local debug compression
+validate_globals_section() {
+ uci_load_validate stunnel globals "$1" "$2" \
+ 'alt_config_file:file' \
+ \
+ 'compression:or("deflate","zlib")' \
+ 'EGD:string' \
+ 'engine:string' \
+ 'engineCtrl:string' \
+ 'engineDefault:list(or("ALL","CIPHERS","DH","DIGESTS","DSA","ECDH","ECDSA","PKEY","PKEY_ASN1","PKEY_CRYPTO","RAND","RSA"))' \
+ 'log:or("append","overwrite")' \
+ 'output:string' \
+ 'RNDbytes:uinteger' \
+ 'RNDfile:string' \
+ 'RNDoverwrite:bool' \
+ 'setgid:or(string,uinteger)' \
+ 'setuid:or(string,uinteger)' \
+ 'syslog:bool' \
+ ;
+}
- config_get alt_config_file 'globals' alt_config_file
- [ -z "$alt_config_file" ] || return 0
+validate_service_section() {
+ uci_load_validate stunnel service "$1" "$2" \
+ 'enabled:bool:1' \
+ \
+ 'setgid:or(string,uinteger)' \
+ 'setuid:or(string,uinteger)' \
+ ;
+}
- # Set default settings
- printf "foreground = yes\n" >> "$CONF_FILE"
- printf "pid = %s\n" "$PID_FILE" >> "$CONF_FILE"
- printf "syslog = yes\n" >> "$CONF_FILE"
+validate_service_options() {
+ uci_load_validate stunnel "$1" "$2" "$3" \
+ 'accept_host:host' \
+ 'accept_port:port' \
+ 'CAfile:string' \
+ 'CApath:string' \
+ 'cert:string' \
+ 'checkEmail:list(string)' \
+ 'checkHost:list(host)' \
+ 'checkIP:list(ipaddr)' \
+ 'ciphers:list(string)' \
+ 'client:bool' \
+ 'config:list(string)' \
+ 'connect:list(string)' \
+ 'CRLfile:string' \
+ 'CRLpath:string' \
+ 'curve:string' \
+ 'debug:or(range(0,7),string)' \
+ 'delay:bool' \
+ 'engineId:string' \
+ 'engineNum:and(uinteger,min(1))' \
+ 'exec:string' \
+ 'execArgs:string' \
+ 'failover:or("prio","rr")' \
+ 'ident:string' \
+ 'include:directory' \
+ 'key:string' \
+ 'local:host' \
+ 'logId:or("process","sequential","thread","unique")' \
+ 'OCSP:string' \
+ 'OCSPaia:bool' \
+ 'OCSPflag:list(or("NOCASIGN","NOCERTS","NOCHAIN","NOCHECKS","NODELEGATED","NOEXPLICIT","NOINTERN","NOSIGS","NOTIME","NOVERIFY","RESPID_KEY","TRUSTOTHER"))' \
+ 'OCSPnonce:bool' \
+ 'options:list(string) ' \
+ 'protocol:or("cifs","connect","imap","nntp","pgsql","pop3","proxy","smtp","socks")' \
+ 'protocolAuthentication:or("basic","login","ntlm","plain")' \
+ 'protocolDomain:hostname' \
+ 'protocolHost_host:host' \
+ 'protocolHost_port:port' \
+ 'protocolPassword:string' \
+ 'protocolUsername:string' \
+ 'PSKidentity:string' \
+ 'PSKsecrets:string' \
+ 'pty:bool' \
+ 'redirect_host:host' \
+ 'redirect_port:port' \
+ 'renegotiation:bool' \
+ 'requireCert:bool' \
+ 'reset:bool' \
+ 'retry:bool' \
+ 'service:string' \
+ 'sessionCacheSize:uinteger' \
+ 'sessionCacheTimeout:uinteger' \
+ 'sessiond_host:host' \
+ 'sessiond_port:port' \
+ 'sni:list(string)' \
+ 'socket:list(string)' \
+ 'sslVersion:or("all","SSLv2","SSLv3","TLSv1","TLSv1.1","TLSv1.2")' \
+ 'stack:uinteger' \
+ 'TIMEOUTbusy:uinteger' \
+ 'TIMEOUTclose:uinteger' \
+ 'TIMEOUTconnect:uinteger' \
+ 'TIMEOUTidle:uinteger' \
+ 'transparent:or("both","destination","none","source")' \
+ 'verifyChain:bool' \
+ 'verifyPeer:bool' \
+ ;
+}
- config_get debug 'globals' debug '5'
- printf "debug = %s\n" "$debug" >> "$CONF_FILE"
+validate_globals_section_service_options() {
+ validate_service_options globals "$@"
+}
- config_get compression 'globals' compression
- [ -z "$compression" ] || printf "compression = %s\n" "$compression" >> "$CONF_FILE"
+validate_service_section_service_options() {
+ validate_service_options service "$@"
}
print_options() {
- local config=$1
- shift
- for opt in "$@"; do
- local $opt
- local value
- local is_boolean=0
-
- if [ "${opt:0:5}" == "bool_" ]; then
- opt="${opt:5}"
- is_boolean=1
- fi
-
- config_get "value" "$config" "$opt"
- [ -z "$value" ] || {
- if [ "$value" = '1' ] && [ "$is_boolean" -eq "1" ]; then
- value="yes"
- elif [ "$value" = '0' ] && [ "$is_boolean" -eq "1" ] ; then
- value="no"
- fi
- printf "%s = %s\n" "$opt" "$value" >> "$CONF_FILE"
+ local _opt
+ local _value
+ for _opt in $*; do
+ eval "_value=\$$_opt"
+ [ -z "$_value" ] || echo "$_opt = $_value" >> "$CONF_FILE"
+ done
+}
+
+print_bool_options() {
+ local _opt
+ local _bool
+ local _value
+ for _opt in $*; do
+ eval "_bool=\$$_opt"
+ [ -z "$_bool" ] || {
+ _value=no
+ [ "$_bool" != 1 ] || _value=yes
+ echo "$_opt = $_value" >> "$CONF_FILE"
}
done
}
-print_list() {
- local config=$1
- shift
- for opt in "$@"; do
- local $opt
- local elements
- config_get "elements" "$config" "$opt"
- for element in $elements; do
- printf "%s = %s\n" "$opt" "$element" >> "$CONF_FILE"
+print_lists_map() {
+ local _opt
+ local _values
+ local _value
+ for _opt in $*; do
+ eval "_values=\$$_opt"
+ for _value in $_values; do
+ echo "$_opt = $_value" >> "$CONF_FILE"
done
done
}
-print_list_colon() {
- local config=$1
- local value
+print_lists_reduce() {
+ local _delim="$1"
+ local _opt
+ local _value
+ local _values
+ local _v
shift
- for opt in "$@"; do
- local $opt
- local elements
- config_get "elements" "$config" "$opt"
- for element in $elements; do
- value="${value}:${element}"
+ for _opt in $*; do
+ _value=
+ eval "_values=\$$_opt"
+ for _v in $_values; do
+ _value=$_value$_delim$_v
done
- printf "%s = %s\n" "$opt" "${value#*:}" >> "$CONF_FILE"
+ _value=${_value#$_delim}
+ [ -z "$_value" ] || echo "$_opt = $_value" >> "$CONF_FILE"
done
}
-service_section() {
- local cfg="$1"
- local accept_host accept_port enabled
+print_host_port() {
+ local _opt
+ local _host
+ local _port
+ for _opt in $*; do
+ eval "_host=\${${_opt}_host}"
+ eval "_port=\${${_opt}_port}"
+ [ -z "$_host" ] || [ -z "$_port" ] || echo "$_opt = $_host:$_port" >> "$CONF_FILE"
+ done
+}
- config_get_bool enabled "$cfg" 'enabled' '1'
- [ ${enabled} -gt 0 ] || return 0
+print_optional_host_port() {
+ local _opt
+ local _host
+ local _port
+ local _value
+ for _opt in $*; do
+ eval "_host=\${${_opt}_host}"
+ eval "_port=\${${_opt}_port}"
+ [ -z "$_port" ] || {
+ _value=$_port
+ [ -z "$_host" ] || _value=$_host:$_port
+ echo "$_opt = $_value" >> "$CONF_FILE"
+ }
+ done
+}
- SERVICE_SECTION_FOUND=1
- printf "\n" >> "$CONF_FILE"
- printf "[%s]\n" "$cfg" >> "$CONF_FILE"
+print_global_options() {
+ print_options \
+ compression \
+ EGD \
+ engine \
+ engineCtrl \
+ log \
+ output \
+ RNDbytes \
+ RNDfile \
+ RNDoverwrite \
+ ;
+
+ print_bool_options \
+ syslog \
+ ;
- config_get accept_host "$cfg" accept_host 'localhost'
- config_get accept_port "$cfg" accept_port
- printf "accept = %s:%s\n" "$accept_host" "$accept_port" >> "$CONF_FILE"
+ print_lists_reduce , \
+ engineDefault \
+ ;
+}
+
+print_service_options() {
+ [ "$2" = 0 ] || {
+ echo "validation failed"
+ return 1
+ }
- print_options "$cfg" CApath \
+ print_options \
CAfile \
+ CApath \
cert \
- CRLpath \
CRLfile \
+ CRLpath \
curve \
- logId \
debug \
+ logId \
engineId \
engineNum \
+ exec \
+ execArgs \
failover \
ident \
+ include \
key \
local \
+ OCSP \
+ protocol \
+ protocolAuthentication \
+ protocolDomain \
+ protocolPassword \
+ protocolUsername \
PSKidentity \
PSKsecrets \
+ service \
+ sessionCacheSize \
+ sessionCacheTimeout \
+ setgid \
+ setuid \
sslVersion \
+ stack \
TIMEOUTbusy \
TIMEOUTclose \
TIMEOUTconnect \
TIMEOUTidle \
- bool_delay \
- bool_libwrap \
- bool_reset \
- bool_requireCert \
- bool_verifyChain \
- bool_verifyPeer \
- bool_client
-
- print_list "$cfg" checkEmail \
+ transparent \
+ ;
+
+ print_bool_options \
+ client \
+ delay \
+ OCSPaia \
+ OCSPnonce \
+ pty \
+ renegotiation \
+ requireCert \
+ reset \
+ retry \
+ verifyChain \
+ verifyPeer \
+ ;
+
+ print_lists_map \
+ checkEmail \
checkHost \
checkIP \
+ config \
connect \
- options
+ OCSPflag \
+ options \
+ sni \
+ socket \
+ ;
- print_list_colon "$cfg" ciphers
-}
+ print_lists_reduce : \
+ ciphers \
+ ;
-process_config() {
- local alt_config_file
+ print_host_port \
+ protocolHost \
+ sessiond \
+ ;
- rm -f "$CONF_FILE"
+ print_optional_host_port \
+ accept \
+ redirect \
+ ;
+}
- # First line
- printf "; STunnel configuration file generated by uci\n" > "$CONF_FILE"
- printf "; Written %s\n\n" "$(date +'%c')" >> "$CONF_FILE"
+create_conf_file() {
+ [ -n "$CONF_FILE_CREATED" ] || {
+ mkdir -p "$(dirname "$CONF_FILE")"
+ echo "; STunnel configuration file generated by uci" > "$CONF_FILE"
+ echo "; Written $(date +'%c')" >> "$CONF_FILE"
+ echo >> "$CONF_FILE"
+ echo "foreground = quiet" >> "$CONF_FILE"
+ echo "pid = $PID_FILE" >> "$CONF_FILE"
+ CONF_FILE_CREATED=1
+ }
+}
- [ -f /etc/config/stunnel ] || return 0
+global_defs() {
+ local pid_dir
- config_load stunnel
- global_defs
+ [ "$2" = 0 ] || {
+ echo "validation failed"
+ return 1
+ }
+
+ # If the first globals section has alt_config_file, don't process any more globals
+ [ -z "$HAVE_ALT_CONF_FILE" ] || return 0
- # If "alt_config_file" specified, use that instead
- [ -n "$alt_config_file" ] && [ -f "$alt_config_file" ] && {
- rm -f "$CONF_FILE"
+ # If "alt_config_file" specified in the first globals section, use that instead
+ [ -z "$alt_config_file" ] || [ -n "$CONF_FILE_CREATED" ] || {
# Symlink "alt_config_file" since it's a bit easier and safer
ln -s "$alt_config_file" "$CONF_FILE"
- # Set section found to start service user hopfully knows what you does
+ # Set section found to start service, user hopefully knows what they are doing
SERVICE_SECTION_FOUND=1
+ CONF_FILE_CREATED=1
+ HAVE_ALT_CONF_FILE=1
return 0
}
- config_foreach service_section service
+ pid_dir="$(dirname "$PID_FILE")"
+ mkdir -p "$pid_dir"
+ [ -z "$setuid" ] || chown "$setuid" "$pid_dir"
+ [ -z "$setgid" ] || chown ":$setgid" "$pid_dir"
+
+ create_conf_file
+ print_global_options
+ validate_service_options globals "$1" print_service_options
+}
+
+service_section() {
+ [ "$2" = 0 ] || {
+ echo "validation failed"
+ return 1
+ }
+
+ [ "$enabled" = 1 ] || return 0
+
+ SERVICE_SECTION_FOUND=1
+ echo >> "$CONF_FILE"
+ echo "[$1]" >> "$CONF_FILE"
+
+ validate_service_options service "$1" print_service_options
}
service_triggers() {
- procd_add_reload_trigger "stunnel"
+ procd_add_reload_trigger stunnel
+
+ procd_open_validate
+ validate_globals_section
+ validate_globals_section_service_options
+ validate_service_section
+ validate_service_section_service_options
+ procd_close_validate
}
start_service() {
- process_config
-
- if [ "$SERVICE_SECTION_FOUND" = 1 ]; then
- procd_open_instance
- procd_set_param command "$BIN"
- procd_append_param command "$CONF_FILE"
- procd_set_param respawn
- procd_set_param file "$CONF_FILE"
- procd_close_instance
- else
+ rm -f "$CONF_FILE"
+ config_load stunnel
+
+ config_foreach validate_globals_section globals global_defs
+
+ [ -n "$HAVE_ALT_CONF_FILE" ] || {
+ create_conf_file
+ config_foreach validate_service_section service service_section
+ }
+
+ [ -n "$SERVICE_SECTION_FOUND" ] || {
logger -t stunnel -p daemon.info "No uci service section enabled or found!"
- fi
+ return 1
+ }
+
+ procd_open_instance
+ procd_set_param command "$BIN"
+ procd_append_param command "$CONF_FILE"
+ procd_set_param respawn
+ procd_set_param file "$CONF_FILE"
+ procd_close_instance
}
diff --git a/net/stunnel/files/stunnel.uci b/net/stunnel/files/stunnel.uci
index 6fad1c6c7..89633ab99 100644
--- a/net/stunnel/files/stunnel.uci
+++ b/net/stunnel/files/stunnel.uci
@@ -1,8 +1,10 @@
config globals 'globals'
- option alt_config_file '/etc/stunnel/stunnel.conf'
- option debug '5'
+ #option alt_config_file '/etc/stunnel/stunnel.conf'
+ option setuid 'nobody'
+ option setgid 'nogroup'
config service 'dummy'
+ option enabled '1'
option client '1'
option accept_host 'localhost'
option accept_port '6000'