diff --git a/packages/ns-don/Makefile b/packages/ns-don/Makefile index 7b39bfa96..0fe1aa8d2 100644 --- a/packages/ns-don/Makefile +++ b/packages/ns-don/Makefile @@ -29,6 +29,11 @@ define Package/ns-don/description Connect to a remote Windmill installation endef +define Package/ns-don/prerm +#!/bin/sh +sed -i '\|/usr/sbin/don expire|d' /etc/crontabs/root +endef + # this is required, otherwise compile will fail define Build/Compile endef @@ -40,6 +45,7 @@ define Package/ns-don/install $(INSTALL_DIR) $(1)/usr/share/nftables.d/chain-pre/input $(INSTALL_BIN) ./files/don $(1)/usr/sbin $(INSTALL_CONF) ./files/20_ns_don $(1)/etc/uci-defaults + $(INSTALL_BIN) ./files/30_don-expire $(1)/etc/uci-defaults $(INSTALL_CONF) ./files/nethesis.pub $(1)/etc/don $(INSTALL_CONF) ./files/nethesis.pem $(1)/etc/don $(INSTALL_DATA) ./files/20-don.nft $(1)/usr/share/nftables.d/chain-pre/input diff --git a/packages/ns-don/files/30_don-expire b/packages/ns-don/files/30_don-expire new file mode 100644 index 000000000..2477e6e4f --- /dev/null +++ b/packages/ns-don/files/30_don-expire @@ -0,0 +1,4 @@ +#!/bin/sh + +grep -q '/usr/sbin/don expire' /etc/crontabs/root 2>/dev/null && exit 0 +echo "0 * * * * sleep $(( RANDOM % 60 )); /usr/sbin/don expire" >> /etc/crontabs/root diff --git a/packages/ns-don/files/don b/packages/ns-don/files/don index 000a7c085..425c18337 100755 --- a/packages/ns-don/files/don +++ b/packages/ns-don/files/don @@ -17,6 +17,8 @@ rsa_key="$base_dir/rsa_key" ecdsa_key="$base_dir/ecdsa_key" socket="$base_dir/management" credentials="$base_dir/credentials" +session_start="$base_dir/session_start" +session_extended="$base_dir/session_extended" user="nethsupport" password="" ca=$(uci -q get don.config.ca) @@ -27,6 +29,18 @@ if [ "$2" == "-j" ]; then json_output=1 fi +function log_message +{ + # Log to /var/log/messages using logger (syslog) + logger -t "don" -p daemon.info "$1" +} + +function log_error +{ + # Log errors to syslog + logger -t "don" -p daemon.err "$1" +} + function cleanup { # stop demons @@ -40,19 +54,57 @@ function cleanup # destroy ubus sessions session=$(ubus call session list | jq -r '.ubus_rpc_session as $parent | .data.username | select(. == "nethsupport") | $parent') if [ "$session" != "" ]; then - ubus call session destroy '{"ubus_rpc_session": "'$session'"}' + ubus call session destroy '{"ubus_rpc_session": "'"$session"'"}' fi + log_message "Remote support session stopped" } -function show_credentials +function get_session_info { + # Both session_start and credentials must be present for a valid session + if [ ! -f "$session_start" ] || [ ! -f "$credentials" ]; then + if [ "$json_output" == 1 ]; then + echo "null" + fi + return 1 + fi + + # Read credentials file into array + mapfile -t creds < "$credentials" + local server_id="${creds[0]}" + local session_id="${creds[1]}" + + local session_start_time + session_start_time=$(cat "$session_start") + local session_expiry + + # Use extended expiry if available, otherwise use start + 24 hours + if [ -f "$session_extended" ]; then + session_expiry=$(cat "$session_extended") + else + session_expiry=$((session_start_time + 86400)) + fi + + local current_time + current_time=$(date +%s) + local time_remaining=$((session_expiry - current_time)) + local hours_remaining=$((time_remaining / 3600)) + local minutes_remaining=$(( (time_remaining % 3600) / 60 )) + if [ "$json_output" == 1 ]; then - echo "{\"server_id\": \"$(sed -n '1{p;q}' $credentials)\", \"session_id\": \"$(sed -n '2{p;q}' $credentials)\"}" + if [ "$time_remaining" -gt 0 ]; then + echo "{\"server_id\": \"$server_id\", \"session_id\": \"$session_id\", \"expires_in_seconds\": $time_remaining, \"expires_in\": \"${hours_remaining}h ${minutes_remaining}m\"}" + else + echo "{\"server_id\": \"$server_id\", \"session_id\": \"$session_id\", \"status\": \"expired\"}" + fi else - echo -n "Server ID:" - echo -e "\t"$(sed -n '1{p;q}' $credentials) - echo -n "Session ID:" - echo -e "\t"$(sed -n '2{p;q}' $credentials) + echo "Server ID:$(printf '\t')$server_id" + echo "Session ID:$(printf '\t')$session_id" + if [ "$time_remaining" -gt 0 ]; then + echo "Session expires in: ${hours_remaining}h ${minutes_remaining}m" + else + echo "Session EXPIRED" + fi fi } @@ -67,11 +119,13 @@ start) system_id=$(uci -q get ns-plug.config.system_id) fi if [ -z "$system_id" ]; then + log_error "Remote support session failed: system_id not configured" exit 2 fi - cn=$(openssl x509 -noout -subject -in $ca | cut -d= -f 2- | sed 's/ = /=/g') + cn=$(openssl x509 -noout -subject -in "$ca" | cut -d= -f 2- | sed 's/ = /=/g') if [ -z "$cn" ]; then + log_error "Remote support session failed: invalid CA certificate" exit 3 fi @@ -162,38 +216,115 @@ AuthorizedKeysFile $auth_keys StrictModes no EOF - mkdir -m 0700 -p /var/empty - /usr/sbin/sshd -f $sshd_conf - cat $(uci -q get don.config.ssh_key) > $auth_keys + mkdir -p /var/empty + chmod 700 /var/empty + /usr/sbin/sshd -f "$sshd_conf" + cat "$(uci -q get don.config.ssh_key)" > "$auth_keys" # Enable UI access uci set rpcd.ns_don=login uci set rpcd.ns_don.username=$user - uci set rpcd.ns_don.password=$(echo $password | mkpasswd) + uci set rpcd.ns_don.password="$(echo "$password" | mkpasswd)" uci add_list rpcd.ns_don.read='*' uci add_list rpcd.ns_don.write='*' # commit rpcd changes uci commit rpcd - show_credentials + # Save session start time + date +%s > "$session_start" + # Mark as not extended initially + rm -f "$session_extended" + log_message "Remote support session started" + + get_session_info ;; stop) cleanup ;; status) - if [ -f $credentials ]; then - show_credentials - exit 0 + if [ -f "$credentials" ]; then + get_session_info + exit 0 else if [ "$json_output" == 1 ]; then echo null else echo "don is not running" fi - exit 1 + exit 1 + fi +;; +expire) + # Check if session has expired - requires both files to be present + if [ ! -f "$session_start" ] || [ ! -f "$credentials" ]; then + if [ "$json_output" == 1 ]; then + echo "{\"status\": \"no_session\"}" + else + echo "No session running" + fi + exit 0 + fi + + session_start_time=$(cat "$session_start") + # Use extended expiry if available, otherwise use start + 24 hours + if [ -f "$session_extended" ]; then + session_expiry=$(cat "$session_extended") + else + session_expiry=$((session_start_time + 86400)) + fi + + current_time=$(date +%s) + time_remaining=$((session_expiry - current_time)) + + if [ "$time_remaining" -le 0 ]; then + # Session has expired - STOP IT NOW + if [ "$json_output" == 1 ]; then + echo "{\"status\": \"expired\", \"action\": \"stopping\"}" + else + echo "Session expired - stopping don service" + fi + log_error "Remote support session expired - auto-disabling" + /usr/sbin/don stop + exit 0 + fi +;; +extend) + # Extend session by 7 days + if [ ! -f "$session_start" ] || [ ! -f "$credentials" ]; then + echo "No session running" + exit 1 + fi + + # Validate that the session has not already expired before allowing extension + session_start_time=$(cat "$session_start") + if [ -f "$session_extended" ]; then + session_expiry=$(cat "$session_extended") + else + session_expiry=$((session_start_time + 86400)) + fi + current_time=$(date +%s) + time_remaining=$((session_expiry - current_time)) + + # Do not extend an already-expired session; the user must start a new one + if [ "$time_remaining" -le 0 ]; then + if [ "$json_output" == 1 ]; then + echo "{\"status\": \"error\", \"message\": \"session already expired\"}" + else + echo "Cannot extend: session already expired" + fi + exit 1 fi + + # Set expiry to 7 days from now + new_expiry=$((current_time + 604800)) + echo "$new_expiry" > "$session_extended" + + # Log the extension + log_message "Remote support session extended by 7 days" + + get_session_info ;; *) - echo "Usage: $0 {start|stop|status} [-j]" + echo "Usage: $0 {start|stop|status|expire|extend} [-j]" exit 2 esac