再次是我。
非常感谢,所有极好的提示和提示都非常有用!也许你可能有心情把我的屁股踢到另一个障碍......
在设置我的Raspberries的过程中,我想通过ssh阻止root登录。与往常一样,它是一个“小脚本”(由跑步者召集)。
我的研究告诉我,即使在systemd时,/ etc / ssh / sshd_config也是要修改的文件。到现在为止还挺好。在我的谦虚理解中,需要做的是:逐行读取配置文件,匹配“PermitRootLogin yes”(空白匹配);如果不匹配,则将该行写入另一个文件,如果是,则将其替换为“PermitRootLogin no”,并写入另一个文件,最后用新文件替换原始配置文件,并通过systemd stuff重新启动sshd。 / p>
在Perl中,我读取整个文件,替换()行,并将东西写回另一个文件。但正如年轻的佛教徒所说:“没有Perl!”
仅限Bash(2)。
并且,一如既往地提前感谢!
的Carsten
答案 0 :(得分:3)
我对此进行了一些调查,我认为JNevevill的回答是最可靠的。
我有一些示例脚本说明了SED
和AWK
这两种方式。
在示例中仅显示测试数据一次以提高可读性。每种方法都已使用相同的方式对其进行了初始化。它将在测试文件中定义一些规则,并提供新规则的字典,这些规则应替换文件中的规则或写入文件。
echo 'LoginGraceTime 120' > ./data.txt
echo '#PermitRootLogin yes' >> ./data.txt
echo 'PermitRootLogin no' >> ./data.txt
echo 'PasswordAuthentication yes' >> ./data.txt
declare -A rules=(
["LoginGraceTime"]="1m"
["PermitRootLogin"]="no"
["PasswordAuthentication"]="no"
["AllowUsers"]="blue"
)
SED
将替换找到的规则。如果一行被注释,它将删除#
并替换该值。这种方法不太可靠,因为它可能导致重复的规则。即存在注释和未注释的规则。另外,如果不存在该规则,则根本不会编写该规则。
for rule in "${!rules[@]}"; do
regex="s/#\?\(${rule}\s*\).*$/\1 ${rules[${rule}]}/"
sed "${regex}" ./data.txt > temp.txt;
mv -f temp.txt ./data.txt
done
结果:
LoginGraceTime 1m
PermitRootLogin no
PermitRootLogin no
PasswordAuthentication no
AWK
在这种情况下会更可靠。它产生更好的控制。
它将逐行读取并替换该值(如果存在)而不更改注释规则。如果在文件末尾没有找到规则,它将把该规则附加到文件中。这比SED
方法更可靠。我们可以确定不会有重复的规则,并且所有规则都已定义。
for rule in "${!rules[@]}"; do
awk -v key="${rule}" -v val="${rules[${rule}]}" \
'$1==key {foundLine=1; print key " " val} $1!=key{print $0} END{if(foundLine!=1) print key " " val}' \
./data.txt > sshd_config.tmp && mv sshd_config.tmp ./data.txt
done
结果:
LoginGraceTime 1m
#PermitRootLogin yes
PermitRootLogin no
PasswordAuthentication no
AllowUsers blue
AWK显然是更好的选择。这样更安全,可以处理文件中未包含的规则。
答案 1 :(得分:2)
脚本:
$ sed -i 's/PermitRootLogin yes/PermitRootLogin no/g' /etc/ssh/sshd_config
然后:
$ service ssh reload
答案 2 :(得分:1)
如果你有GNU sed 4.2.2,你可以使用以下技巧:
sed -z 's/PermitRootLogin yes\|$/PermitRootLogin no/' file
-z
将读取由NUL(\0
)分隔的行,因此基本上在sed中启用slurp模式
-i
将对您的文件进行现场编辑,因此请记住在使用它之前进行备份
替换很简单:
将PermitRootLogin yes
替换为PermitRootLogin no
,如果找不到,请将PermitRootLogin no
追加到最后。
您可以在搜索周围添加字词边界:\<PermitRootLogin yes\>
请注意,如果PermitRootLogin yes
未匹配,则省略了跟踪换行符,因为PermitRootLogin no
将在最后一个换行符后插入。
答案 3 :(得分:1)
你可以做那样的事情
#!/bin/bash
if [[ "${UID}" -ne 0 ]]; then
echo " You need to run this script as root"
exit 1
fi
#To directly modify sshd_config.
sed -i 's/#\?\(Port\s*\).*$/\1 2231/' /etc/ssh/sshd_config
sed -i 's/#\?\(PerminRootLogin\s*\).*$/\1 no/' /etc/ssh/sshd_config
sed -i 's/#\?\(PubkeyAuthentication\s*\).*$/\1 yes/' /etc/ssh/sshd_config
sed -i 's/#\?\(PermitEmptyPasswords\s*\).*$/\1 no/' /etc/ssh/sshd_config
sed -i 's/#\?\(PasswordAuthentication\s*\).*$/\1 no/' /etc/ssh/sshd_config
#Check the exit status of the last command
if [[ "${?}" -ne 0 ]]; then
echo "The sshd_config file was not modified successfully"
exit 1
fi
/etc/init.d/ssh restart
exit 0
答案 4 :(得分:0)
您可以使用awk
:
awk '$1=="PermitRootLogin"{foundLine=1; print "PermitRootLogin no"} $1!="PermitRootLogin"{print $0} END{if(foundLine!=1) print "permitRootLogin no"}' sshd_config > sshd_config.tmp && mv sshd_config.tmp sshd_config
如果第一个元素(由awk的默认delim分隔)是“PermitRootLogin”然后将其更改为“no”并捕获您找到它,则遍历文件中的每一行。如果该行不包含“PermitRootLogin”,则按原样将其写出。如果在处理完所有行(END
)后没有找到“PermitRootLogin”,则写入该行。
答案 5 :(得分:0)
@cyrus:
我当前的脚本如下所示:
#!/bin/bash
touch /tmp/sshd_config
while read -r line || [[ -n "$line" ]]; do
if [ "$line" = "PermitRootLogin yes" ]; then
match=1
echo "PermitRootLogin no" >> /tmp/sshd_config
else
echo "$line" >> /tmp/sshd_config
fi
done < /etc/ssh/sshd_config
if [ "$match" != "1" ]; then
echo "PermitRootLogin no" >> /tmp/sshd_config
fi
它有效,但看起来很糟糕。我更喜欢更多的\ s +'ish样式来捕获“PermitRootLogin(manySpaces)yes”和“PermitRootLogin(tabTabTab)yes”行。使用'grep'的方法肯定会更好。
到目前为止已经回答并提到sed和awk的任何人:你的提案中有三个警告。 1:我,因为我不是发行版的维护者,不能保证将安装一个或两个。 2:我不知道是否有人想要修改我的脚本是sed和/或awk破解。 3:我可以保证,除了sed和awk是华丽的,令人敬畏的,优雅的工具来处理这些东西之外,我对sed和awk完全不了解。是的,这是一个令人羞辱的差距。
====== 后脚本......
在玩了一下并在原始剧本中找到一个丑陋的警告之后,这是我当前的版本:
#!/bin/bash
INFILE=/etc/ssh/sshd_config
TMPFILE=/var/tmp/sshd_config
touch $TMPFILE
while read -r line || [[ -n "$line" ]]; do
if [ `echo "$line" | grep -c -P "^\s*PermitRootLogin\s+"` = "1" ]; then
match=1
echo "PermitRootLogin no" >> $TMPFILE
else
echo "$line" >> $TMPFILE
fi
done < $INFILE
if [ "$match" != "1" ]; then
echo "" >> $TMPFILE
echo "# Do not permit root to log in directly" >> $TMPFILE
echo "PermitRootLogin no" >> $TMPFILE
fi
cp -f $TMPFILE $INFILE
sync
与旧版本的不同之处在于,从简单比较到grep的变化,但是pcre确实是必要的。如果未来的发行版附带“PermitRootLogin no”,则前一版本将为配置添加至少不必要的条目。另一个漂亮的事情是,另一行的配置文件在注释中包含“PermitRootLogin yes”。一个简单的grep -c -P“PermitRootLogin \ s + yes”就会匹配(再次)。
新版本仍然看起来笨拙和丑陋,但它有效:)
答案 6 :(得分:0)
这可以进一步简化为一些线性脚本,您可以在其中传递要更改的变量,并且可以随时为您更改。检查各种语法,并确保最终结果都完美完成。
是和否也可以转换为交换机
致用户脚本
replace_string.sh sshd_config.old PasswordAuthentication PermitRootLogin
我的脚本看起来像这样
#! /bin/bash
sshd_config_file=$1
search_replace()
{
grep -i "^${search_string} yes$" ${sshd_config_file} | grep -v "^#"|grep -v "${search_string} no" || sed -i "" "s|^#*${search_string}.*$|${search_string} yes|" ${sshd_config_file}
}
#for search_string in $@; do
for search_string in $(eval echo ${*:2}); do
search_replace
done