mirror of
https://github.com/opnsense/src.git
synced 2026-02-18 18:20:26 -05:00
nuageinit: implement chpasswd
Add support for chpasswd, with all possible syntaxes, including deprecated one: chpasswd.list as a list or as a multiline string as some providers are still only providing this deprecated form Approved by: re (cperciva) Sponsored by: OVHCloud MFC After: 1 week Reviewed by: kevans, jlduran Differential Revision: https://reviews.freebsd.org/D50021 (cherry picked from commit c201a1198ad70e7d096ee32c364d539eed2dfec4) (cherry picked from commit 6c912470030ba958f2e41a00b44f6430919b1389)
This commit is contained in:
parent
f30669ba97
commit
b64d3fc884
3 changed files with 283 additions and 3 deletions
|
|
@ -1,7 +1,7 @@
|
|||
---
|
||||
-- SPDX-License-Identifier: BSD-2-Clause
|
||||
--
|
||||
-- Copyright(c) 2022 Baptiste Daroussin <bapt@FreeBSD.org>
|
||||
-- Copyright(c) 2022-2025 Baptiste Daroussin <bapt@FreeBSD.org>
|
||||
|
||||
local unistd = require("posix.unistd")
|
||||
local sys_stat = require("posix.sys.stat")
|
||||
|
|
@ -261,6 +261,106 @@ local function update_sshd_config(key, value)
|
|||
os.rename(sshd_config .. ".nuageinit", sshd_config)
|
||||
end
|
||||
|
||||
local function exec_change_password(user, password, type, expire)
|
||||
local root = os.getenv("NUAGE_FAKE_ROOTDIR")
|
||||
local cmd = "pw "
|
||||
if root then
|
||||
cmd = cmd .. "-R " .. root .. " "
|
||||
end
|
||||
local postcmd = " -H 0"
|
||||
local input = password
|
||||
if type ~= nil and type == "text" then
|
||||
postcmd = " -h 0"
|
||||
else
|
||||
if password == "RANDOM" then
|
||||
input = nil
|
||||
postcmd = " -w random"
|
||||
end
|
||||
end
|
||||
cmd = cmd .. "usermod " .. user .. postcmd
|
||||
if expire then
|
||||
cmd = cmd .. " -p 1"
|
||||
else
|
||||
cmd = cmd .. " -p 0"
|
||||
end
|
||||
local f = io.popen(cmd .. " >/dev/null", "w")
|
||||
if input then
|
||||
f:write(input)
|
||||
end
|
||||
-- ignore stdout to avoid printing the password in case of random password
|
||||
local r = f:close(cmd)
|
||||
if not r then
|
||||
warnmsg("fail to change user password ".. user)
|
||||
warnmsg(cmd)
|
||||
end
|
||||
end
|
||||
|
||||
local function change_password_from_line(line, expire)
|
||||
local user, password = line:match("%s*(%w+):(%S+)%s*")
|
||||
local type = nil
|
||||
if user and password then
|
||||
if password == "R" then
|
||||
password = "RANDOM"
|
||||
end
|
||||
if not password:match("^%$%d+%$%w+%$") then
|
||||
if password ~= "RANDOM" then
|
||||
type = "text"
|
||||
end
|
||||
end
|
||||
exec_change_password(user, password, type, expire)
|
||||
end
|
||||
end
|
||||
|
||||
local function chpasswd(obj)
|
||||
if type(obj) ~= "table" then
|
||||
warnmsg("Invalid chpasswd entry, expecting an object")
|
||||
return
|
||||
end
|
||||
local expire = false
|
||||
if obj.expire ~= nil then
|
||||
if type(obj.expire) == "boolean" then
|
||||
expire = obj.expire
|
||||
else
|
||||
warnmsg("Invalid type for chpasswd.expire, expecting a boolean, got a ".. type(obj.expire))
|
||||
end
|
||||
end
|
||||
if obj.users ~= nil then
|
||||
if type(obj.users) ~= "table" then
|
||||
warnmsg("Invalid type for chpasswd.users, expecting a list, got a ".. type(obj.users))
|
||||
goto list
|
||||
end
|
||||
for _, u in ipairs(obj.users) do
|
||||
if type(u) ~= "table" then
|
||||
warnmsg("Invalid chpasswd.users entry, expecting an object, got a " .. type(u))
|
||||
goto next
|
||||
end
|
||||
if not u.name then
|
||||
warnmsg("Invalid entry for chpasswd.users: missing 'name'")
|
||||
goto next
|
||||
end
|
||||
if not u.password then
|
||||
warnmsg("Invalid entry for chpasswd.users: missing 'password'")
|
||||
goto next
|
||||
end
|
||||
exec_change_password(u.name, u.password, u.type, expire)
|
||||
::next::
|
||||
end
|
||||
end
|
||||
::list::
|
||||
if obj.list ~= nil then
|
||||
warnmsg("chpasswd.list is deprecated consider using chpasswd.users")
|
||||
if type(obj.list) == "string" then
|
||||
for line in obj.list:gmatch("[^\n]+") do
|
||||
change_password_from_line(line, expire)
|
||||
end
|
||||
elseif type(obj.list) == "table" then
|
||||
for _, u in ipairs(obj.list) do
|
||||
change_password_from_line(u, expire)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local n = {
|
||||
warn = warnmsg,
|
||||
err = errmsg,
|
||||
|
|
@ -270,7 +370,8 @@ local n = {
|
|||
adduser = adduser,
|
||||
addgroup = addgroup,
|
||||
addsshkey = addsshkey,
|
||||
update_sshd_config = update_sshd_config
|
||||
update_sshd_config = update_sshd_config,
|
||||
chpasswd = chpasswd
|
||||
}
|
||||
|
||||
return n
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
---
|
||||
-- SPDX-License-Identifier: BSD-2-Clause-FreeBSD
|
||||
--
|
||||
-- Copyright(c) 2022 Baptiste Daroussin <bapt@FreeBSD.org>
|
||||
-- Copyright(c) 2022-2025 Baptiste Daroussin <bapt@FreeBSD.org>
|
||||
|
||||
local nuage = require("nuage")
|
||||
local ucl = require("ucl")
|
||||
|
|
@ -359,6 +359,10 @@ if line == "#cloud-config" then
|
|||
end
|
||||
nuage.update_sshd_config("PasswordAuthentication", value)
|
||||
end
|
||||
if obj.chpasswd ~= nil then
|
||||
nuage.chpasswd(obj.chpasswd)
|
||||
end
|
||||
|
||||
else
|
||||
local res, err = os.execute(path .. "/" .. ud)
|
||||
if not res then
|
||||
|
|
|
|||
|
|
@ -20,6 +20,9 @@ atf_test_case config2_network
|
|||
atf_test_case config2_network_static_v4
|
||||
atf_test_case config2_ssh_keys
|
||||
atf_test_case nocloud_userdata_cloudconfig_ssh_pwauth
|
||||
atf_test_case nocloud_userdata_cloudconfig_chpasswd
|
||||
atf_test_case nocloud_userdata_cloudconfig_chpasswd_list_string
|
||||
atf_test_case nocloud_userdata_cloudconfig_chpasswd_list_list
|
||||
|
||||
args_body()
|
||||
{
|
||||
|
|
@ -512,6 +515,175 @@ EOF
|
|||
atf_check -o inline:"PasswordAuthentication no\n" cat etc/ssh/sshd_config
|
||||
}
|
||||
|
||||
nocloud_userdata_cloudconfig_chpasswd_head()
|
||||
{
|
||||
atf_set "require.user" root
|
||||
}
|
||||
nocloud_userdata_cloudconfig_chpasswd_body()
|
||||
{
|
||||
mkdir -p etc
|
||||
cat > etc/master.passwd << EOF
|
||||
root:*:0:0::0:0:Charlie &:/root:/bin/sh
|
||||
sys:*:1:0::0:0:Sys:/home/sys:/bin/sh
|
||||
user:*:1:0::0:0:Sys:/home/sys:/bin/sh
|
||||
EOF
|
||||
pwd_mkdb -d etc "${PWD}"/etc/master.passwd
|
||||
cat > etc/group << EOF
|
||||
wheel:*:0:root
|
||||
users:*:1:
|
||||
EOF
|
||||
mkdir -p media/nuageinit
|
||||
printf "instance-id: iid-local01\n" > "${PWD}"/media/nuageinit/meta-data
|
||||
cat > media/nuageinit/user-data << 'EOF'
|
||||
#cloud-config
|
||||
chpasswd:
|
||||
expire: true
|
||||
users:
|
||||
- { user: "sys", password: RANDOM }
|
||||
EOF
|
||||
|
||||
atf_check -o empty -e inline:"nuageinit: Invalid entry for chpasswd.users: missing 'name'\n" /usr/libexec/nuageinit "${PWD}"/media/nuageinit nocloud
|
||||
# nothing modified
|
||||
atf_check -o inline:"sys:*:1:0::0:0:Sys:/home/sys:/bin/sh\n" pw -R $(pwd) usershow sys
|
||||
|
||||
cat > media/nuageinit/user-data << 'EOF'
|
||||
#cloud-config
|
||||
chpasswd:
|
||||
expire: true
|
||||
users:
|
||||
- { name: "sys", pwd: RANDOM }
|
||||
EOF
|
||||
atf_check -o empty -e inline:"nuageinit: Invalid entry for chpasswd.users: missing 'password'\n" /usr/libexec/nuageinit "${PWD}"/media/nuageinit nocloud
|
||||
# nothing modified
|
||||
atf_check -o inline:"sys:*:1:0::0:0:Sys:/home/sys:/bin/sh\n" pw -R $(pwd) usershow sys
|
||||
|
||||
cat > media/nuageinit/user-data << 'EOF'
|
||||
#cloud-config
|
||||
chpasswd:
|
||||
expire: false
|
||||
users:
|
||||
- { name: "sys", password: RANDOM }
|
||||
EOF
|
||||
# not empty because the password is printed to stdout
|
||||
atf_check -o empty -e empty /usr/libexec/nuageinit "${PWD}"/media/nuageinit nocloud
|
||||
atf_check -o match:'sys:\$.*:1:0::0:0:Sys:/home/sys:/bin/sh$' pw -R $(pwd) usershow sys
|
||||
|
||||
cat > media/nuageinit/user-data << 'EOF'
|
||||
#cloud-config
|
||||
chpasswd:
|
||||
expire: true
|
||||
users:
|
||||
- { name: "sys", password: RANDOM }
|
||||
EOF
|
||||
# not empty because the password is printed to stdout
|
||||
atf_check -o empty -e empty /usr/libexec/nuageinit "${PWD}"/media/nuageinit nocloud
|
||||
atf_check -o match:'sys:\$.*:1:0::1:0:Sys:/home/sys:/bin/sh$' pw -R $(pwd) usershow sys
|
||||
|
||||
cat > media/nuageinit/user-data << 'EOF'
|
||||
#cloud-config
|
||||
chpasswd:
|
||||
expire: true
|
||||
users:
|
||||
- { name: "user", password: "$6$j212wezy$7H/1LT4f9/N3wpgNunhsIqtMj62OKiS3nyNwuizouQc3u7MbYCarYeAHWYPYb2FT.lbioDm2RrkJPb9BZMN1O/" }
|
||||
EOF
|
||||
# not empty because the password is printed to stdout
|
||||
atf_check -o empty -e empty /usr/libexec/nuageinit "${PWD}"/media/nuageinit nocloud
|
||||
atf_check -o inline:'user:$6$j212wezy$7H/1LT4f9/N3wpgNunhsIqtMj62OKiS3nyNwuizouQc3u7MbYCarYeAHWYPYb2FT.lbioDm2RrkJPb9BZMN1O/:1:0::1:0:Sys:/home/sys:/bin/sh\n' pw -R $(pwd) usershow user
|
||||
}
|
||||
|
||||
|
||||
nocloud_userdata_cloudconfig_chpasswd_list_string_head()
|
||||
{
|
||||
atf_set "require.user" root
|
||||
}
|
||||
nocloud_userdata_cloudconfig_chpasswd_list_string_body()
|
||||
{
|
||||
mkdir -p etc
|
||||
cat > etc/master.passwd << EOF
|
||||
root:*:0:0::0:0:Charlie &:/root:/bin/sh
|
||||
sys:*:1:0::0:0:Sys:/home/sys:/bin/sh
|
||||
user:*:1:0::0:0:Sys:/home/sys:/bin/sh
|
||||
EOF
|
||||
pwd_mkdb -d etc "${PWD}"/etc/master.passwd
|
||||
cat > etc/group << EOF
|
||||
wheel:*:0:root
|
||||
users:*:1:
|
||||
EOF
|
||||
mkdir -p media/nuageinit
|
||||
printf "instance-id: iid-local01\n" > "${PWD}"/media/nuageinit/meta-data
|
||||
cat > media/nuageinit/user-data << 'EOF'
|
||||
#cloud-config
|
||||
chpasswd:
|
||||
expire: true
|
||||
list: |
|
||||
sys:RANDOM
|
||||
EOF
|
||||
|
||||
atf_check -o empty -e inline:"nuageinit: chpasswd.list is deprecated consider using chpasswd.users\n" /usr/libexec/nuageinit "${PWD}"/media/nuageinit nocloud
|
||||
atf_check -o match:'sys:\$.*:1:0::1:0:Sys:/home/sys:/bin/sh$' pw -R $(pwd) usershow sys
|
||||
|
||||
cat > media/nuageinit/user-data << 'EOF'
|
||||
#cloud-config
|
||||
chpasswd:
|
||||
expire: false
|
||||
list: |
|
||||
sys:plop
|
||||
user:$6$j212wezy$7H/1LT4f9/N3wpgNunhsIqtMj62OKiS3nyNwuizouQc3u7MbYCarYeAHWYPYb2FT.lbioDm2RrkJPb9BZMN1O/
|
||||
root:R
|
||||
EOF
|
||||
|
||||
atf_check -o empty -e ignore /usr/libexec/nuageinit "${PWD}"/media/nuageinit nocloud
|
||||
atf_check -o match:'sys:\$.*:1:0::0:0:Sys:/home/sys:/bin/sh$' pw -R $(pwd) usershow sys
|
||||
atf_check -o inline:'user:$6$j212wezy$7H/1LT4f9/N3wpgNunhsIqtMj62OKiS3nyNwuizouQc3u7MbYCarYeAHWYPYb2FT.lbioDm2RrkJPb9BZMN1O/:1:0::0:0:Sys:/home/sys:/bin/sh\n' pw -R $(pwd) usershow user
|
||||
atf_check -o match:'root:\$.*:0:0::0:0:Charlie &:/root:/bin/sh$' pw -R $(pwd) usershow root
|
||||
}
|
||||
|
||||
nocloud_userdata_cloudconfig_chpasswd_list_list_head()
|
||||
{
|
||||
atf_set "require.user" root
|
||||
}
|
||||
nocloud_userdata_cloudconfig_chpasswd_list_list_body()
|
||||
{
|
||||
mkdir -p etc
|
||||
cat > etc/master.passwd << EOF
|
||||
root:*:0:0::0:0:Charlie &:/root:/bin/sh
|
||||
sys:*:1:0::0:0:Sys:/home/sys:/bin/sh
|
||||
user:*:1:0::0:0:Sys:/home/sys:/bin/sh
|
||||
EOF
|
||||
pwd_mkdb -d etc "${PWD}"/etc/master.passwd
|
||||
cat > etc/group << EOF
|
||||
wheel:*:0:root
|
||||
users:*:1:
|
||||
EOF
|
||||
mkdir -p media/nuageinit
|
||||
printf "instance-id: iid-local01\n" > "${PWD}"/media/nuageinit/meta-data
|
||||
cat > media/nuageinit/user-data << 'EOF'
|
||||
#cloud-config
|
||||
chpasswd:
|
||||
expire: true
|
||||
list:
|
||||
- sys:RANDOM
|
||||
EOF
|
||||
|
||||
atf_check -o empty -e inline:"nuageinit: chpasswd.list is deprecated consider using chpasswd.users\n" /usr/libexec/nuageinit "${PWD}"/media/nuageinit nocloud
|
||||
atf_check -o match:'sys:\$.*:1:0::1:0:Sys:/home/sys:/bin/sh$' pw -R $(pwd) usershow sys
|
||||
|
||||
cat > media/nuageinit/user-data << 'EOF'
|
||||
#cloud-config
|
||||
chpasswd:
|
||||
expire: false
|
||||
list:
|
||||
- sys:plop
|
||||
- user:$6$j212wezy$7H/1LT4f9/N3wpgNunhsIqtMj62OKiS3nyNwuizouQc3u7MbYCarYeAHWYPYb2FT.lbioDm2RrkJPb9BZMN1O/
|
||||
- root:R
|
||||
EOF
|
||||
|
||||
atf_check -o empty -e ignore /usr/libexec/nuageinit "${PWD}"/media/nuageinit nocloud
|
||||
atf_check -o match:'sys:\$.*:1:0::0:0:Sys:/home/sys:/bin/sh$' pw -R $(pwd) usershow sys
|
||||
atf_check -o inline:'user:$6$j212wezy$7H/1LT4f9/N3wpgNunhsIqtMj62OKiS3nyNwuizouQc3u7MbYCarYeAHWYPYb2FT.lbioDm2RrkJPb9BZMN1O/:1:0::0:0:Sys:/home/sys:/bin/sh\n' pw -R $(pwd) usershow user
|
||||
atf_check -o match:'root:\$.*:0:0::0:0:Charlie &:/root:/bin/sh$' pw -R $(pwd) usershow root
|
||||
}
|
||||
|
||||
atf_init_test_cases()
|
||||
{
|
||||
atf_add_test_case args
|
||||
|
|
@ -528,4 +700,7 @@ atf_init_test_cases()
|
|||
atf_add_test_case config2_network_static_v4
|
||||
atf_add_test_case config2_ssh_keys
|
||||
atf_add_test_case nocloud_userdata_cloudconfig_ssh_pwauth
|
||||
atf_add_test_case nocloud_userdata_cloudconfig_chpasswd
|
||||
atf_add_test_case nocloud_userdata_cloudconfig_chpasswd_list_string
|
||||
atf_add_test_case nocloud_userdata_cloudconfig_chpasswd_list_list
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue