115 lines
5.3 KiB
Bash
Executable File
115 lines
5.3 KiB
Bash
Executable File
#!/bin/bash
|
|
# FILE: admin/user/add
|
|
# DESCRIPTION: Add a new user from admin UI
|
|
# USAGE: add $remote_ip $querystring
|
|
# QUERYSTRING: ?t=$token&host=$hostname&user=$username
|
|
|
|
source /etc/wgapi/config
|
|
ip="${1}"; qs="$(<<<"${2}" tr '&' '\n' | sed 's/?//')"
|
|
|
|
# Check token
|
|
token_fail(){
|
|
printf 'Rejecting admin %s request for new peer due to %s token\n' "${ip}" "${1}" >&2
|
|
printf 'Invalid token\n' | /usr/lib/wgapi/http_res 403; exit
|
|
}
|
|
saved_token="$(grep "${ip}" /var/local/wgapi/tokens | cut -f2)"
|
|
[ "${saved_token}" == "" ] && token_fail 'missing' &
|
|
<<<"${qs}" grep -qx "t=${saved_token}" || token_fail 'mismatched'
|
|
printf '%s token was valid\n' "${ip}" >&2
|
|
|
|
# Parse new hostname and new username
|
|
hostname="$(<<<"${qs}" grep -oP 'host=(.*)' | sed 's/^host=//' | xargs | tr -dc 'a-z0-9' | head -c10)"
|
|
username="$(<<<"${qs}" grep -oP 'user=(.*)' | sed 's/^user=//' | xargs | tr -dc 'a-z0-9' | head -c10)"
|
|
if ! domain="${hostname:?}.${username:?}.${TLD:?}"; then
|
|
printf 'ERROR! Hostname "%s" or username "%s" or tld "%s" missing!\n' "${hostname}" "${username}" "${TLD}" >&2
|
|
printf 'Hostname or username missing!\n' | /usr/lib/wgapi/http_res 400; exit
|
|
else
|
|
printf 'Admin %s requested new user created with initial peer of %s\n' "${ip}" "${domain}" >&2
|
|
fi
|
|
if ! [[ ${#hostname} -ge 3 ]]; then
|
|
printf 'Rejecting hostname %s because it is too short.\n' "${hostname}" >&2
|
|
printf 'Hostname too short\n' | /usr/lib/wgapi/http_res 400; exit
|
|
elif ! [[ ${#username} -ge 3 ]]; then
|
|
printf 'Rejecting username %s because it is too short.\n' "${username}" >&2
|
|
printf 'Username too short\n' | /usr/lib/wgapi/http_res 400; exit
|
|
fi
|
|
|
|
# Check if user already exists
|
|
if /usr/lib/wgapi/ns_lookup_rxfr | grep ".${username}.${TLD}" >/dev/null; then
|
|
printf 'User %s already exists!\n' "${username}" | tee >(cat 1>&2) | /usr/lib/wgapi/http_res 409
|
|
exit
|
|
fi
|
|
|
|
# Get all peer IPs
|
|
if ! peers="$(sudo /usr/bin/wg show "${TLD}" allowed-ips)"; then
|
|
printf 'ERROR! Wireguard failed!\n' >&2
|
|
/usr/lib/wgapi/http_res 500; exit
|
|
fi
|
|
|
|
# Create new IPs
|
|
hostnumber='1'
|
|
ipv4s="$(printf '%s\n' "${peers}" | awk '{print $2,$3}' | tr ' ' '\n' | grep '\.' | cut -d'/' -f1)"
|
|
#ipv6s="$(printf '%s\n' "${peers}" | awk '{print $2,$3}' | tr ' ' '\n' | grep '\:' | cut -d'/' -f1)"
|
|
# Increment hostnumber from 1 until an unused one is found
|
|
used_usernumbers="$(<<<"${ipv4s}" cut -d'.' -f3 | sort | uniq)"
|
|
usernumber=1; while <<<"${used_usernumbers}" grep -q "${usernumber}"
|
|
do ((usernumber++))
|
|
done
|
|
ipv4="${IPV4_NET%.*.*}.${usernumber}.${hostnumber}"
|
|
ipv6="${IPV6_NET%:*:*}:${usernumber}:${hostnumber}"
|
|
if ! printf 'IP addresses for %s created: %s %s\n' "${domain:?}" "${ipv4:?}" "${ipv6:?}" >&2; then
|
|
printf 'ERROR! Failed to create IP addresses for %s!' "${domain}" >&2
|
|
/usr/lib/wgapi/http_res 500; exit
|
|
fi
|
|
|
|
# Create wg config
|
|
privkey="$(/usr/bin/wg genkey)"
|
|
pubkey="$(echo "${privkey}" | /usr/bin/wg pubkey)"
|
|
address="${ipv4}/${IPV4_NET##*/},${ipv6}/${IPV6_NET##*/}"
|
|
|
|
# Update nameserver
|
|
if /usr/lib/wgapi/ns_update_add "${domain:?}" "${ipv4:?}" "${ipv6:?}"
|
|
then printf 'Successfully added %s to DNS server.\n' "${domain}" >&2
|
|
else printf 'ERROR! Failed to add %s %s %s to DNS server!\n' "${domain}" "${ipv4}" "${ipv6}" >&2
|
|
fi &
|
|
|
|
# Create SSL cert
|
|
if ! sudo mkdir "${SSL_CONFIG_DIR:?}/${username:?}/"; then
|
|
printf 'Failed to create directory %s/%s/:\n' "${SSL_CONFIG_DIR}" "${username}" >&2
|
|
/usr/lib/wgapi/http_res 500; exit
|
|
fi
|
|
if /usr/lib/wgapi/ssl_peer_add "${hostname:?}" "${username:?}" "IP:${ipv4},IP:${ipv6}"
|
|
then printf 'Successfully signed SSL certs for %s\n' "${domain}" >&2
|
|
else printf 'ERROR! Failed to create certs for %s with IPS: %s %s!\n' "${domain}" "${ipv4}" "${ipv6}" >&2
|
|
fi
|
|
|
|
# Do the wireguard and tell the user
|
|
server_blocks=''
|
|
while IFS=$'\t' read -r server_hostname server_ipv4 server_ipv6 server_pubkey server_endpoint server_url server_secret; do
|
|
[[ ${server_hostname:0:1} = \# ]] && continue
|
|
server_psk="$(/usr/bin/wg genpsk)"
|
|
# Local server
|
|
if [ "${server_hostname}" == "${LOCAL_SERVER}" ]; then
|
|
server_blocks="${server_blocks}\n[Peer] # ${server_hostname}.${TLD}\nPublicKey=${server_pubkey}\nPresharedKey=${server_psk}\nAllowedIPs=${server_ipv4}/${IPV4_NET#*/},${server_ipv6}/${IPV6_NET#*/}\nEndpoint=${server_endpoint}\n"
|
|
# Add new user to local wireguard
|
|
if /usr/lib/wgapi/wg_peer_add "${pubkey}" "${server_psk}" "${ipv4}/32,${ipv6}/128"; then
|
|
printf 'Added %s to local wireguard server.\n' "${domain}" >&2
|
|
else
|
|
printf 'ERROR! Failed to add %s to local wireguard server!\n' "${domain}" >&2
|
|
# TODO: clear existing progress
|
|
/usr/lib/wgapi/http_res 500; exit
|
|
fi
|
|
# Remote server
|
|
else
|
|
server_blocks="${server_blocks}\n[Peer] # ${server_hostname}.${TLD}\nPublicKey=${server_pubkey}\nPresharedKey=${server_psk}\nAllowedIPs=${server_ipv4}/32,${server_ipv6}/128\nEndpoint=${server_endpoint}\n"
|
|
# Send new user config to federated server
|
|
if /usr/lib/wgapi/fed_peer_add "${server_url}" "${server_secret}" "${pubkey}" "${server_psk}" "${ipv4}/32,${ipv6}/128" "${server_secret}"; then
|
|
printf 'Sent %s to remote wireguard server %s.\n' "${domain}" "${server_hostname}" >&2
|
|
else
|
|
printf 'ERROR! Failed to send %s to remote wireguard server %s!\n' "${domain}" "${server_hostname}" >&2
|
|
fi
|
|
fi
|
|
done </etc/wgapi/servers
|
|
wg_config="[Interface] # ${hostname}.${username}.${TLD}\nPrivateKey=${privkey:?}\nAddress=${address:?}\n${WG_DNS}\n${server_blocks:?}"
|
|
<<<"${wg_config}" /usr/lib/wgapi/http_res 202
|