Browse Source

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>
lilik-openwrt-22.03
Jeffery To 6 years ago
parent
commit
8bb3eba3c2
3 changed files with 333 additions and 109 deletions
  1. +1
    -1
      net/stunnel/Makefile
  2. +328
    -106
      net/stunnel/files/stunnel.init
  3. +4
    -2
      net/stunnel/files/stunnel.uci

+ 1
- 1
net/stunnel/Makefile View File

@ -9,7 +9,7 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=stunnel
PKG_VERSION:=5.49
PKG_RELEASE:=1
PKG_RELEASE:=2
PKG_LICENSE:=GPL-2.0+
PKG_MAINTAINER:=Florian Eckert <fe@dev.tdt.de>


+ 328
- 106
net/stunnel/files/stunnel.init View File

@ -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
}

+ 4
- 2
net/stunnel/files/stunnel.uci View File

@ -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'


Loading…
Cancel
Save