--- /dev/null
+#
+# Copyright (C) 2025 The Atsign Foundation
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=csshnpd
+PKG_VERSION:=1.0.12
+PKG_RELEASE:=1
+
+PKG_SOURCE:=$(PKG_NAME)-c$(PKG_VERSION).tar.gz
+PKG_SOURCE_URL:=https://github.com/atsign-foundation/noports/releases/download/c$(PKG_VERSION)
+PKG_HASH:=02990724a29cc5a879e1ed282699a8b12fdcc008a9ab3acbfc987cd2ecdab7e4
+
+PKG_LICENSE:=BSD-3-Clause
+PKG_LICENSE_FILES:=LICENSE
+
+PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-c$(PKG_VERSION)
+
+include $(INCLUDE_DIR)/package.mk
+include $(INCLUDE_DIR)/cmake.mk
+
+CMAKE_OPTIONS += \
+ -S . \
+ -DATSDK_BUILD_TESTS="OFF" \
+ -DATSDK_MEMCHECK="OFF" \
+ -DBUILD_SHARED_AND_STATIC_LIBS="OFF" \
+ -DCMAKE_EXPORT_COMPILE_COMMANDS="OFF" \
+ -DCMAKE_INSTALL_PREFIX="${PKG_BUILD_DIR}/build/release-static/tmp-install-dir" \
+ -DENABLE_PROGRAMS="OFF" \
+ -DENABLE_TARGET_EXPORT="OFF" \
+ -DENABLE_TESTING="OFF" \
+ -DNOPORTS_ATSDK_PATH="deps/atsdk-src" \
+ -DNOPORTS_BUILD_TESTS="OFF" \
+ -DNOPORTS_USE_SHARED_LIBS="ON"
+
+define Package/csshnpd
+ SECTION:=net
+ CATEGORY:=Network
+ SUBMENU:=SSH
+ DEPENDS:=+libmbedtls +cJSON
+ TITLE:=NoPorts Daemon
+ URL:=https://noports.com
+endef
+
+define Package/csshnpd/description
+ A small and portable daemon for NoPorts.
+endef
+
+define Package/csshnpd/conffiles
+/etc/config/sshnpd
+endef
+
+define Package/csshnpd/install
+ $(INSTALL_DIR) $(1)/usr/bin
+ $(INSTALL_BIN) $(PKG_BUILD_DIR)/sshnpd/sshnpd $(1)/usr/bin/
+ $(INSTALL_BIN) $(PKG_BUILD_DIR)/sshnpd/at_activate $(1)/usr/bin/
+ $(INSTALL_BIN) ./files/at_enroll.sh $(1)/usr/bin/
+
+ $(INSTALL_DIR) $(1)/etc/config
+ $(INSTALL_CONF) ./files/csshnpd.config $(1)/etc/config/sshnpd
+
+ $(INSTALL_DIR) $(1)/etc/init.d
+ $(INSTALL_BIN) ./files/csshnpd.init $(1)/etc/init.d/sshnpd
+endef
+
+$(eval $(call BuildPackage,csshnpd))
--- /dev/null
+#!/bin/sh
+. /lib/functions.sh
+enroll_atsign() {
+ local section="$1"
+
+ config_get atsign "$section" "atsign"
+ if [ -z "$atsign" ]; then
+ echo "sshnpd: atsign must be configured in /etc/config/sshnpd"
+ return 1
+ fi
+
+ config_get device "$section" "device"
+ if [ -z "$device" ]; then
+ echo "sshnpd: device must be configured in /etc/config/sshnpd"
+ return 1
+ fi
+
+ config_get otp "$section" "otp"
+ if [ -z "$otp" ]; then
+ echo "sshnpd: otp must be configured in /etc/config/sshnpd"
+ return 1
+ fi
+
+ config_get user "$section" user
+ if [ -z "$user" ]; then
+ user='root'
+ fi
+
+ config_get home "$section" home
+ if [ -z "$home" ]; then
+ if [ "$user" = "root" ]; then
+ home='/root'
+ else
+ home="/home/${user}"
+ fi
+ fi
+
+ if [ ! -d "${home}/.atsign/keys" ]; then
+ mkdir -p "${home}/.atsign/keys"
+ fi
+
+ if [ -f "${home}/.atsign/keys/${atsign}_key.atKeys" ]; then
+ echo "sshnpd: atsign keys file already present, exiting enrollment"
+ return 1
+ fi
+
+ echo
+ echo "To activate this enrollment run the following command line on a"
+ echo "system where the ${atsign} key has been activated:"
+ echo
+ echo "at_activate approve -a ${atsign} --arx noports --drx ${device}"
+ echo
+
+ at_activate enroll -a ${atsign} -s ${otp} -p noports \
+ -k ${home}/.atsign/keys/${atsign}_key.atKeys -d ${device} \
+ -n "sshnp:rw,sshrvd:rw"
+
+}
+config_load sshnpd
+config_foreach enroll_atsign sshnpd
--- /dev/null
+config sshnpd
+ option atsign '@atsign'
+ option manager '@manager'
+ option device 'devicename'
+ option args ''
+ option otp ''
+ option enabled '0'
--- /dev/null
+#!/bin/sh /etc/rc.common
+# Copyright (C) 2007-2011 OpenWrt.org
+
+USE_PROCD=1
+START=80
+
+start_instance() {
+ local section="$1"
+
+ config_get_bool enabled "$section" enabled 1
+ [ "$enabled" != "1" ] && return 0
+
+ config_get atsign "$section" atsign
+ if [ -z "$atsign" ]; then
+ echo "sshnpd: atsign for this device is mandatory"
+ return 1
+ fi
+
+ config_get manager "$section" manager
+ if [ -z "$manager" ]; then
+ echo "sshnpd: manager for this device is mandatory"
+ return 1
+ fi
+
+ config_get device "$section" device
+ if [ -z "$device" ]; then
+ echo "sshnpd: device name is mandatory"
+ return 1
+ fi
+
+ config_get user "$section" user
+ if [ -z "$user" ]; then
+ user='root'
+ fi
+
+ config_get home "$section" home
+ if [ -z "$home" ]; then
+ if [ "$user" = "root" ]; then
+ home='/root'
+ else
+ home="/home/${user}"
+ fi
+ fi
+
+ if [ ! -f "${home}/.atsign/keys/${atsign}_key.atKeys" ]; then
+ echo "sshnpd: WARNING atsign keys not found in default location"
+ fi
+
+ if [ ! -d "${home}/.ssh" ]; then
+ mkdir ${home}/.ssh
+ chmod 700 ${home}/.ssh
+ fi
+
+ if [ ! -f "${home}/.ssh/authorized_keys" ]; then
+ touch ${home}/.ssh/authorized_keys
+ chmod 600 ${home}/.ssh/authorized_keys
+ fi
+
+ config_get args "$section" args
+
+ config_get pidfile "$section" pidfile
+
+ procd_open_instance "$section"
+ procd_set_param stdout 1
+ procd_set_param stderr 1
+ procd_set_param env USER=${user} HOME=${home}
+ procd_set_param command /usr/bin/sshnpd -a ${atsign} -m ${manager} -d ${device} ${args}
+ procd_set_param respawn ${respawn_threshold:-3600} ${respawn_timeout:-5} ${respawn_retry:-5}
+ [ -n "$pidfile" ] && procd_set_param pidfile "$pidfile"
+
+ [ -n "$pidfile" ] && procd_append_param env "SSHNPD_PIDFILE=$pidfile"
+
+ procd_close_instance
+}
+
+start_service() {
+ local instance=$1
+
+ config_load 'sshnpd'
+
+ if [ -n "$instance" ]; then
+ start_instance "$1"
+ else
+ config_foreach start_instance 'sshnpd'
+ fi
+}
--- /dev/null
+#!/bin/sh
+
+sshnpd --help | grep "$2"