mirror of
https://dev.iopsys.eu/feed/iopsys.git
synced 2025-12-10 07:44:50 +01:00
Merge branch 'hmehdi_ssh_mfa' into 'devel'
sshmngr: generate pam config and add MFA support See merge request feed/iopsys!1877
This commit is contained in:
commit
c462b123e2
7 changed files with 399 additions and 1 deletions
|
|
@ -28,4 +28,15 @@ config SSHMNGR_SFTP
|
||||||
default y
|
default y
|
||||||
help
|
help
|
||||||
Enable this option to support the SFTP protocol.
|
Enable this option to support the SFTP protocol.
|
||||||
|
|
||||||
|
config SSHMNGR_SECURITY_MFA
|
||||||
|
bool "MFA using PAM and Google authenticator"
|
||||||
|
depends on SSHMNGR_BACKEND_OPENSSH_PAM
|
||||||
|
default n
|
||||||
|
help
|
||||||
|
Enable this option to use MFA with PAM based Google authenticator.
|
||||||
|
|
||||||
|
config SSHMNGR_VENDOR_PREFIX
|
||||||
|
string "Package specific datamodel Vendor Prefix for TR181 extensions"
|
||||||
|
default ""
|
||||||
endif
|
endif
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,7 @@ define Package/sshmngr
|
||||||
DEPENDS+=+SSHMNGR_BACKEND_OPENSSH_PAM:openssh-server-pam +SSHMNGR_BACKEND_OPENSSH_PAM:openssh-client-utils
|
DEPENDS+=+SSHMNGR_BACKEND_OPENSSH_PAM:openssh-server-pam +SSHMNGR_BACKEND_OPENSSH_PAM:openssh-client-utils
|
||||||
DEPENDS+=+SSHMNGR_BACKEND_DROPBEAR:dropbear
|
DEPENDS+=+SSHMNGR_BACKEND_DROPBEAR:dropbear
|
||||||
DEPENDS+=+SSHMNGR_SFTP:openssh-sftp-server
|
DEPENDS+=+SSHMNGR_SFTP:openssh-sftp-server
|
||||||
|
DEPENDS+=+SSHMNGR_SECURITY_MFA:google-authenticator-libpam
|
||||||
endef
|
endef
|
||||||
|
|
||||||
define Package/sshmngr/description
|
define Package/sshmngr/description
|
||||||
|
|
@ -44,6 +45,13 @@ define Package/$(PKG_NAME)/config
|
||||||
source "$(SOURCE)/Config.in"
|
source "$(SOURCE)/Config.in"
|
||||||
endef
|
endef
|
||||||
|
|
||||||
|
ifeq ($(CONFIG_SSHMNGR_VENDOR_PREFIX),"")
|
||||||
|
VENDOR_PREFIX = $(CONFIG_BBF_VENDOR_PREFIX)
|
||||||
|
else
|
||||||
|
VENDOR_PREFIX = $(CONFIG_SSHMNGR_VENDOR_PREFIX)
|
||||||
|
endif
|
||||||
|
|
||||||
|
|
||||||
ifeq ($(LOCAL_DEV),1)
|
ifeq ($(LOCAL_DEV),1)
|
||||||
define Build/Prepare
|
define Build/Prepare
|
||||||
$(CP) -rf ./sshmngr/* $(PKG_BUILD_DIR)/
|
$(CP) -rf ./sshmngr/* $(PKG_BUILD_DIR)/
|
||||||
|
|
@ -67,6 +75,16 @@ endif
|
||||||
$(BBFDM_REGISTER_SERVICES) ./bbfdm_service.json $(1) $(PKG_NAME)
|
$(BBFDM_REGISTER_SERVICES) ./bbfdm_service.json $(1) $(PKG_NAME)
|
||||||
$(BBFDM_INSTALL_MS_DM) $(PKG_BUILD_DIR)/src/libsshmngr.so $(1) $(PKG_NAME)
|
$(BBFDM_INSTALL_MS_DM) $(PKG_BUILD_DIR)/src/libsshmngr.so $(1) $(PKG_NAME)
|
||||||
|
|
||||||
|
ifeq ($(CONFIG_SSHMNGR_BACKEND_OPENSSH_PAM),y)
|
||||||
|
$(INSTALL_DIR) $(1)/etc/uci-defaults
|
||||||
|
$(INSTALL_DATA) ./files/openssh_backend/lib/sshmngr/pam_config.sh $(1)/lib/sshmngr/
|
||||||
|
$(INSTALL_BIN) ./files/openssh_backend/etc/uci-defaults/91-set-sshd-pam $(1)/etc/uci-defaults/
|
||||||
|
ifeq ($(CONFIG_SSHMNGR_SECURITY_MFA),y)
|
||||||
|
$(INSTALL_BIN) ./files/openssh_backend/etc/uci-defaults/92-set-ssh-mfa $(1)/etc/uci-defaults/
|
||||||
|
$(BBFDM_INSTALL_MS_PLUGIN) -v ${VENDOR_PREFIX} ./files/openssh_backend/ssh_mfa_override.json $(1) $(PKG_NAME)
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
ifeq ($(CONFIG_PACKAGE_fail2ban),y)
|
ifeq ($(CONFIG_PACKAGE_fail2ban),y)
|
||||||
$(INSTALL_DIR) $(1)/etc/fail2ban/jail.d
|
$(INSTALL_DIR) $(1)/etc/fail2ban/jail.d
|
||||||
$(INSTALL_DIR) $(1)/etc/fail2ban/filter.d/
|
$(INSTALL_DIR) $(1)/etc/fail2ban/filter.d/
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,8 @@
|
||||||
. /usr/share/libubox/jshn.sh
|
. /usr/share/libubox/jshn.sh
|
||||||
. /lib/sshmngr/backend.sh
|
. /lib/sshmngr/backend.sh
|
||||||
|
|
||||||
|
MFA_SECRET_FILE="/etc/security/mfa_secret"
|
||||||
|
|
||||||
add_server_name()
|
add_server_name()
|
||||||
{
|
{
|
||||||
local server_sec="${1}"
|
local server_sec="${1}"
|
||||||
|
|
@ -44,7 +46,7 @@ get_pid()
|
||||||
|
|
||||||
case "$1" in
|
case "$1" in
|
||||||
list)
|
list)
|
||||||
echo '{ "dump" : {"server_name":"string"}, "kill_session" : {"session_pid":"string","server_name":"string"}, "list_keys" : {}, "add_pubkey" : {"current_key":"string","new_key":"string"}, "remove_pubkey" : {"key":"string"} }'
|
echo '{ "dump" : {"server_name":"string"}, "kill_session" : {"session_pid":"string","server_name":"string"}, "list_keys" : {}, "add_pubkey" : {"current_key":"string","new_key":"string"}, "remove_pubkey" : {"key":"string"}, "get_mfa_key" : {}, "get_mfa_recovery" : {} }'
|
||||||
;;
|
;;
|
||||||
call)
|
call)
|
||||||
case "$2" in
|
case "$2" in
|
||||||
|
|
@ -221,6 +223,31 @@ case "$1" in
|
||||||
fi
|
fi
|
||||||
echo '{}'
|
echo '{}'
|
||||||
;;
|
;;
|
||||||
|
|
||||||
|
get_mfa_key)
|
||||||
|
mfa_key=""
|
||||||
|
if [ -f "${MFA_SECRET_FILE}" ]; then
|
||||||
|
mfa_key="$(head -n 1 "$MFA_SECRET_FILE" 2>/dev/null)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
json_init
|
||||||
|
json_add_string "mfa_key" "${mfa_key}"
|
||||||
|
json_dump
|
||||||
|
;;
|
||||||
|
|
||||||
|
get_mfa_recovery)
|
||||||
|
mfa_recovery_codes=""
|
||||||
|
|
||||||
|
if [ -f "${MFA_SECRET_FILE}" ]; then
|
||||||
|
mfa_recovery_codes="$(tail -n 3 "$MFA_SECRET_FILE" 2>/dev/null | tr '\n' ',')"
|
||||||
|
# remove trailing comma
|
||||||
|
mfa_recovery_codes="${mfa_recovery_codes%,}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
json_init
|
||||||
|
json_add_string "recovery_codes" "${mfa_recovery_codes}"
|
||||||
|
json_dump
|
||||||
|
;;
|
||||||
esac
|
esac
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# create or over-write our desired file
|
||||||
|
# /etc/pam.d/sshd
|
||||||
|
cat << 'EOF' > /etc/pam.d/sshd
|
||||||
|
auth required pam_env.so
|
||||||
|
auth include sshd-auth
|
||||||
|
account required pam_nologin.so
|
||||||
|
account include sshd-account
|
||||||
|
session include common-session
|
||||||
|
session required pam_limits.so
|
||||||
|
password include sshd-password
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# /etc/pam.d/sshd-auth
|
||||||
|
cat << 'EOF' > /etc/pam.d/sshd-auth
|
||||||
|
auth [success=1 default=ignore] pam_unix.so nullok_secure
|
||||||
|
auth requisite pam_deny.so
|
||||||
|
auth required pam_permit.so
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# /etc/pam.d/sshd-password
|
||||||
|
cat << 'EOF' > /etc/pam.d/sshd-password
|
||||||
|
password [success=1 default=ignore] pam_unix.so sha512
|
||||||
|
password requisite pam_deny.so
|
||||||
|
password required pam_permit.so
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# /etc/pam.d/sshd-account
|
||||||
|
cat << 'EOF' > /etc/pam.d/sshd-account
|
||||||
|
account [success=1 new_authtok_reqd=done default=ignore] pam_unix.so
|
||||||
|
account requisite pam_deny.so
|
||||||
|
account required pam_permit.so
|
||||||
|
EOF
|
||||||
|
|
||||||
|
exit 0
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
if [ -f /etc/config/sshd ]; then
|
||||||
|
# make sure not to change already existing setting
|
||||||
|
if ! uci -q get sshd.@sshd[0].UseMFA 2>&1 > /dev/null; then
|
||||||
|
uci -q set sshd.@sshd[0].UseMFA=1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
exit 0
|
||||||
228
sshmngr/files/openssh_backend/lib/sshmngr/pam_config.sh
Executable file
228
sshmngr/files/openssh_backend/lib/sshmngr/pam_config.sh
Executable file
|
|
@ -0,0 +1,228 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# List of required .so files
|
||||||
|
REQUIRED_MODULES="
|
||||||
|
/usr/lib/security/pam_faildelay.so
|
||||||
|
/usr/lib/security/pam_faillock.so
|
||||||
|
/usr/lib/security/pam_unix.so
|
||||||
|
/usr/lib/security/pam_deny.so
|
||||||
|
/usr/lib/security/pam_permit.so
|
||||||
|
/usr/lib/security/pam_passwdqc.so
|
||||||
|
"
|
||||||
|
|
||||||
|
MFA_APP="google-authenticator"
|
||||||
|
MFA_LIB="/usr/lib/security/pam_google_authenticator.so"
|
||||||
|
MFA_DIR="/etc/security"
|
||||||
|
MFA_SECRET_FILE="${MFA_DIR}/mfa_secret"
|
||||||
|
MFA_QR_FILE="${MFA_DIR}/mfa_qr"
|
||||||
|
|
||||||
|
log() {
|
||||||
|
echo "$*" | logger -t sshd.init -p info
|
||||||
|
}
|
||||||
|
|
||||||
|
log_err() {
|
||||||
|
echo "$*" | logger -t sshd.init -p err
|
||||||
|
}
|
||||||
|
|
||||||
|
check_required_modules() {
|
||||||
|
for mod in $REQUIRED_MODULES; do
|
||||||
|
if [ ! -f "$mod" ]; then
|
||||||
|
log_err "ERROR: Cannot setup security policy, missing PAM module: $mod"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
write_line() {
|
||||||
|
local filepath="$1"
|
||||||
|
local line="$2"
|
||||||
|
|
||||||
|
echo "$line" >> "$filepath"
|
||||||
|
}
|
||||||
|
|
||||||
|
compare_and_replace() {
|
||||||
|
local src dst
|
||||||
|
src="$1"
|
||||||
|
dst="$2"
|
||||||
|
|
||||||
|
if [ ! -f "$dst" ] || ! cmp -s "$src" "$dst"; then
|
||||||
|
cp "$src" "$dst"
|
||||||
|
log "Updated $dst"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
setup_mfa() {
|
||||||
|
mkdir -p "$MFA_DIR"
|
||||||
|
|
||||||
|
if [ -f "${MFA_SECRET_FILE}" ] && [ -f "${MFA_QR_FILE}" ]; then
|
||||||
|
log "Not updating MFA files, they already exist"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
touch "$MFA_SECRET_FILE"
|
||||||
|
touch "$MFA_QR_FILE"
|
||||||
|
chmod 600 "$MFA_SECRET_FILE"
|
||||||
|
chmod 600 "$MFA_QR_FILE"
|
||||||
|
|
||||||
|
local cmd="$MFA_APP -f -s $MFA_SECRET_FILE -C -t -d -r 3 -R 30 -w 3 -Q UTF8 -e 3"
|
||||||
|
|
||||||
|
log "Running MFA app: $cmd"
|
||||||
|
# if the google-authenticator senses that the output is not going to a terminal
|
||||||
|
# then it does not print out the QR, so simple redirection does not work
|
||||||
|
# we have to run the command inside a pseudo-terminal using script command
|
||||||
|
# and then redirect that output to a file
|
||||||
|
cmd="script -q -c \"$cmd\" $MFA_QR_FILE > /dev/null"
|
||||||
|
eval "$cmd"
|
||||||
|
}
|
||||||
|
|
||||||
|
update_auth() {
|
||||||
|
# Write /etc/pam.d/sshd-auth
|
||||||
|
local tmp_file pam_file
|
||||||
|
tmp_file="/tmp/sshd-auth"
|
||||||
|
pam_file="/etc/pam.d/sshd-auth"
|
||||||
|
|
||||||
|
local auth_enabled="${1}"
|
||||||
|
local enabled="${2}"
|
||||||
|
local mfa_enabled="${3}"
|
||||||
|
|
||||||
|
local faildelay="$(uci -q get users.authentication_policy.fail_delay || echo 3)"
|
||||||
|
local faillock_lockout_time="$(uci -q get users.authentication_policy.faillock_lockout_time || echo 300)"
|
||||||
|
local faillock_attempts="$(uci -q get users.authentication_policy.faillock_attempts || echo 6)"
|
||||||
|
|
||||||
|
# Convert seconds to microseconds for pam_faildelay
|
||||||
|
local faildelay_usec=$((faildelay * 1000000))
|
||||||
|
|
||||||
|
rm -f "$tmp_file"
|
||||||
|
touch "$tmp_file"
|
||||||
|
|
||||||
|
if [ "${auth_enabled}" -eq 1 ] && [ "${enabled}" -eq 1 ]; then
|
||||||
|
write_line "$tmp_file" "auth optional pam_faildelay.so delay=$faildelay_usec"
|
||||||
|
write_line "$tmp_file" "auth required pam_faillock.so preauth deny=$faillock_attempts even_deny_root unlock_time=$faillock_lockout_time"
|
||||||
|
fi
|
||||||
|
|
||||||
|
write_line "$tmp_file" "auth [success=1 default=bad] pam_unix.so nullok_secure"
|
||||||
|
write_line "$tmp_file" "auth [default=die] pam_faillock.so authfail audit deny=$faillock_attempts even_deny_root unlock_time=$faillock_lockout_time"
|
||||||
|
|
||||||
|
if [ "$mfa_enabled" -eq 1 ]; then
|
||||||
|
write_line "$tmp_file" "auth [success=1 default=bad] pam_google_authenticator.so secret=$MFA_SECRET_FILE"
|
||||||
|
write_line "$tmp_file" "auth [default=die] pam_faillock.so authfail audit deny=$faillock_attempts even_deny_root unlock_time=$faillock_lockout_time"
|
||||||
|
fi
|
||||||
|
|
||||||
|
write_line "$tmp_file" "auth sufficient pam_faillock.so authsucc audit deny=$faillock_attempts even_deny_root unlock_time=$faillock_lockout_time"
|
||||||
|
|
||||||
|
write_line "$tmp_file" "auth requisite pam_deny.so"
|
||||||
|
|
||||||
|
compare_and_replace "$tmp_file" "$pam_file"
|
||||||
|
}
|
||||||
|
|
||||||
|
build_pam_passwdqc_line() {
|
||||||
|
local base="password requisite pam_passwdqc.so"
|
||||||
|
local k v line
|
||||||
|
|
||||||
|
for line in $(uci show users.passwdqc 2>/dev/null); do
|
||||||
|
case "$line" in
|
||||||
|
users.passwdqc=*) continue ;;
|
||||||
|
users.passwdqc.enabled=*) continue ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
k="${line%%=*}"
|
||||||
|
k="${k#users.passwdqc.}"
|
||||||
|
v="${line#*=}"
|
||||||
|
v="${v%\'}"
|
||||||
|
v="${v#\'}"
|
||||||
|
base="$base $k=$v"
|
||||||
|
done
|
||||||
|
|
||||||
|
base="$base match=0"
|
||||||
|
|
||||||
|
echo "$base"
|
||||||
|
}
|
||||||
|
|
||||||
|
# NOTE:
|
||||||
|
# for some reason setting min 8 makes passwdqc accept minimum 12 letter password with this configuration
|
||||||
|
# if we set it to 12 then we need atleast 16 characters and so on
|
||||||
|
# passphrase = 0 means no space separated words
|
||||||
|
# passphrase = N means the number of words required for a passphrase or 0 to disable the support for user-chosen passphrases.
|
||||||
|
# rest can be figured out from passwdqc man page
|
||||||
|
update_password() {
|
||||||
|
local tmp_file pam_file enabled line
|
||||||
|
tmp_file="/tmp/sshd-password"
|
||||||
|
pam_file="/etc/pam.d/sshd-password"
|
||||||
|
|
||||||
|
local auth_enabled="${1}"
|
||||||
|
|
||||||
|
rm -f "$tmp_file"
|
||||||
|
touch "$tmp_file"
|
||||||
|
|
||||||
|
# Check if section exists
|
||||||
|
if uci -q get users.passwdqc >/dev/null 2>&1; then
|
||||||
|
# if enabled is not present it is assumed to be 0
|
||||||
|
enabled=$(uci -q get users.passwdqc.enabled || echo "0")
|
||||||
|
if [ "${auth_enabled}" -eq 1 ] && [ "${enabled}" -eq 1 ]; then
|
||||||
|
line="$(build_pam_passwdqc_line)"
|
||||||
|
write_line "$tmp_file" "$line"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
write_line "$tmp_file" "password [success=1 default=ignore] pam_unix.so sha512"
|
||||||
|
write_line "$tmp_file" ""
|
||||||
|
write_line "$tmp_file" "password requisite pam_deny.so"
|
||||||
|
write_line "$tmp_file" "password required pam_permit.so"
|
||||||
|
|
||||||
|
compare_and_replace "$tmp_file" "$pam_file"
|
||||||
|
}
|
||||||
|
|
||||||
|
update_account() {
|
||||||
|
# Write /etc/pam.d/sshd-account
|
||||||
|
local tmp_file pam_file
|
||||||
|
tmp_file="/tmp/sshd-account"
|
||||||
|
pam_file="/etc/pam.d/sshd-account"
|
||||||
|
|
||||||
|
local auth_enabled="${1}"
|
||||||
|
local enabled="${2}"
|
||||||
|
|
||||||
|
rm -f "$tmp_file"
|
||||||
|
touch "$tmp_file"
|
||||||
|
|
||||||
|
if [ "${auth_enabled}" -eq 1 ] && [ "${enabled}" -eq 1 ]; then
|
||||||
|
write_line "$tmp_file" "account required pam_faillock.so"
|
||||||
|
fi
|
||||||
|
|
||||||
|
write_line "$tmp_file" "account [success=1 new_authtok_reqd=done default=ignore] pam_unix.so"
|
||||||
|
write_line "$tmp_file" ""
|
||||||
|
write_line "$tmp_file" "account requisite pam_deny.so"
|
||||||
|
write_line "$tmp_file" "account required pam_permit.so"
|
||||||
|
|
||||||
|
compare_and_replace "$tmp_file" "$pam_file"
|
||||||
|
}
|
||||||
|
|
||||||
|
handle_security_policy() {
|
||||||
|
local auth_enabled enabled
|
||||||
|
local use_mfa mfa_enabled
|
||||||
|
|
||||||
|
# Read UCI values
|
||||||
|
auth_enabled="$(uci -q get users.users.auth_policy_enable || echo 0)"
|
||||||
|
enabled="$(uci -q get users.authentication_policy.enabled || echo 0)"
|
||||||
|
use_mfa="$(uci -q get sshd.@sshd[0].UseMFA || echo 0)"
|
||||||
|
|
||||||
|
# if any .so files are missing, then we cannot setup security
|
||||||
|
if ! check_required_modules; then
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Detect and enable MFA only if requested and module exists
|
||||||
|
if which "$MFA_APP" > /dev/null 2>&1 && [ "$use_mfa" = "1" ] && [ -f "$MFA_LIB" ]; then
|
||||||
|
mfa_enabled=1
|
||||||
|
setup_mfa
|
||||||
|
else
|
||||||
|
rm -rf "${MFA_QR_FILE}"
|
||||||
|
rm -rf "${MFA_SECRET_FILE}"
|
||||||
|
mfa_enabled=0
|
||||||
|
fi
|
||||||
|
|
||||||
|
update_auth "${auth_enabled}" "${enabled}" "${mfa_enabled}"
|
||||||
|
update_account "${auth_enabled}" "${enabled}"
|
||||||
|
update_password "${auth_enabled}"
|
||||||
|
}
|
||||||
68
sshmngr/files/openssh_backend/ssh_mfa_override.json
Normal file
68
sshmngr/files/openssh_backend/ssh_mfa_override.json
Normal file
|
|
@ -0,0 +1,68 @@
|
||||||
|
{
|
||||||
|
"json_plugin_version": 2,
|
||||||
|
"Device.SSH.Server.{i}.": {
|
||||||
|
"type": "object",
|
||||||
|
"protocols": [
|
||||||
|
"cwmp",
|
||||||
|
"usp"
|
||||||
|
],
|
||||||
|
"access": false,
|
||||||
|
"array": false,
|
||||||
|
"{BBF_VENDOR_PREFIX}UseMFA": {
|
||||||
|
"type": "boolean",
|
||||||
|
"read": true,
|
||||||
|
"write": true,
|
||||||
|
"protocols": [
|
||||||
|
"cwmp",
|
||||||
|
"usp"
|
||||||
|
],
|
||||||
|
"mapping": [
|
||||||
|
{
|
||||||
|
"data": "@Parent",
|
||||||
|
"type": "uci_sec",
|
||||||
|
"key": "UseMFA"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"{BBF_VENDOR_PREFIX}MFA_Key": {
|
||||||
|
"type": "string",
|
||||||
|
"read": true,
|
||||||
|
"write": false,
|
||||||
|
"protocols": [
|
||||||
|
"cwmp",
|
||||||
|
"usp"
|
||||||
|
],
|
||||||
|
"mapping": [
|
||||||
|
{
|
||||||
|
"type": "ubus",
|
||||||
|
"ubus": {
|
||||||
|
"object": "sshmngr",
|
||||||
|
"method": "get_mfa_key",
|
||||||
|
"args": {},
|
||||||
|
"key": "mfa_key"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"{BBF_VENDOR_PREFIX}MFA_Recovery_Codes": {
|
||||||
|
"type": "string",
|
||||||
|
"read": true,
|
||||||
|
"write": false,
|
||||||
|
"protocols": [
|
||||||
|
"cwmp",
|
||||||
|
"usp"
|
||||||
|
],
|
||||||
|
"mapping": [
|
||||||
|
{
|
||||||
|
"type": "ubus",
|
||||||
|
"ubus": {
|
||||||
|
"object": "sshmngr",
|
||||||
|
"method": "get_mfa_recovery",
|
||||||
|
"args": {},
|
||||||
|
"key": "recovery_codes"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue