http://blog.csdn.net/siberiabear/article/details/52249218
向嵌入式linux开发板移植openSSH
晚上没事干,想着能不能把高大上的openSSH移植到我现在开发的嵌入式linux开发板上,前不久刚弄出来dropbear,但遇到一些小问题,一会说,所以把openSSH搞上去还是可以的。开发板端为服务器端,由宿主机客户端访问。
2016-8-16
背景
- 开发板:freescale i.mx6q
- 宿主机操作系统:ubuntu 14.04
- 开发板操作系统:linux 3.0.35
基本情况
使用dropbear后,ssh算是在板子上成功跑起来了,参见我另一篇日记,然而,在使用的过程中,需要对root用户重新设置一次密码后,才可以正常操作,然而,由于我对板子本身编译进去的ftp不了解,重新设置root密码后,就无法使用ftp传输文件了。了解到dropbear自带了scp协议一个简单文件传输工具,于是就开始搞,后来没搞出来。然后去研究如何把sftp加入到dropbear中,过程需要编译openSSH并提取sftp。得了,就直接搞openSSH吧。
经后来测试,编译后的openSSH可执行文件约为16M,确实足够大了,还好板子上的内存容量还足够。开启一个shell后的运行内存基本忽略,还是可以用的,最关键openSSH里还带有sftp,scp等工具,简直方便。
步骤
编译
1.需要用到的源码包有:openssh,openssl,zlib,请按下列地址下载:
openssh-7.3:
http://ftp.openbsd.org/pub/OpenBSD/OpenSSH/openssh-7.3.tar.gz
openssl-1.0.1t:
https://www.openssl.org/source/openssl-1.0.1t.tar.gz
zlib-1.2.8:
http://zlib.net/zlib-1.2.8.tar.gz
请登录网站选择合适的版本下载。
2.首先编译zlib,这里不再重复写,参考我之前的日记(向嵌入式linux开发板移植dropbear)
3.编译openssl:openssl根目录下:
~
~
~
~
4.编译openssh:openssh源码根目录下:
. --- -- --- ---- ----- --- ---- ----
这里创建
/usr/local/openssh
并没有作用,openssh是要运行在开发机的,在宿主机中
make install
没有意义,这里是习惯性做法。另外,网上的技术帖子说将本地的路径作为打包路径一并打包,也是一种做法,但我认为略显麻烦或混乱,我最终是用脚本按部署所有的openssh工具的。
第二句命令配置configure,其中
--disable-etc-default-login
是
disable using PATH from /etc/default/login no
;
--disable-strip
是
disable calling strip(1) on install
,不大清楚有啥用,先记着了。第一次编译时没有添加这个参数,但最终还是设置成功了。
然后接着,在openssh源码路径下:
~
这里不需要
make install
,上边说过。据我印象,这次make会产生一些问题,都是与设置交叉编译链有关系的,如果遇到问题,就在Makefile文件中做对应的修改。
开发机
在开发机中新建以下目录:
/usr/local/openssh/bin
/usr/local/openssh/etc
/usr/local/libexec
/var/run
/var/empty
openSSH编译之后,会生成好多可执行文件,我们将以下文件上传到开发机的固定位置。
以下文件拷贝到开发机
/usr/local/openssh/bin
目录下:
scp sftp ssh ssh-add ssh-agent ssh-keygen ssh-keyscan
以下文件拷贝到开发机
/usr/local/openssh/etc
目录下:
moduli ssh_config sshd_config
以下文件拷贝到开发机
/usr/local/libexec
目录下:
sftp-server ssh-keysign
注意: 这里可能应该把
sftp-server
拷贝到
/usr/libexec
路径下,与
sshd_config
配置文件的设置默认路径相匹配,我没有实际试过,但应该是这样的,下边会有详细叙述。
以下文件拷贝到开发机
/etc/rc.d/init.d
目录下:
sshd
8-19 补充:这里可能有些不合理的操作,在
/etc/rc.d/init.d
路径下,默认是一些脚本文件,包装调用对应同名二进制程序的脚本,增加一些文件判断,启停命令,而不是直接调用二进制程序,我们这里把二进制文件放在这里,是可以实现功能的,但做法不完全合理。一种做法是,将
sshd
文件拷贝到
/sbin/sshd
目录下,而在
/etc/rc.d/init.d
目录下添加一个脚本文件,同名,脚本内容见文末。(我是按照补充部分的做法实现的)
另注:将二进制程序放到
/etc/rc.d/init.d
中,而在
/sbin
目录中增加软链接的方式,不是错误的,也有这么做的,比如
busybox
程序在
/sbin
目录下建立了所有相关程序的软连接到
/bin/busybox
,是可以实现的,个人投其所好吧。
建立软链接:
~
~/bin # ln -s /usr/local/openssh/bin/scp
~/bin # ln -s /usr/local/openssh/bin/sftp
~/bin # ln -s /usr/local/openssh/bin/ssh
~/bin # ln -s /usr/local/openssh/bin/ssh-add
~/bin # ln -s /usr/local/openssh/bin/ssh-agent
~/bin # ln -s /usr/local/openssh/bin/ssh-keygen
~/bin # ln -s /usr/local/openssh/bin/ssh-keyscan
~
~/sbin # ln -s /etc/rc.d/init.d/sshd
这里的最后一句:
~/sbin # ln -s /etc/rc.d/init.d/sshd
是对的,但有另一种方案,如上边
8-19 补充
所述。
开发板配置
在开发板上创建sshd的工作目录和用户:(第一次编译时,并没有做这一步操作,有待之后验证)
~ # addgroup sshd
~ # adduser -G sshd -g 'sshd privsep' -h /var/empty -s /bin/ssh sshd
8-17补充:并没有作用,sshd用户默认系统给定了,只不过是禁止登陆状态,需要修改
/etc/passwd
文件,或给sshd重新设定密码。这一步可以暂时不做,往下看。
在目标机上产生证书密码对:
~
~/usr/local/openssh/etc
~/usr/local/openssh/etc
~/usr/local/openssh/etc
~/usr/local/openssh/etc
~/usr/local/openssh/etc
配置完这部分后,
etc
目录下产生很多密码对,另外,这里遇到一个问题,我配置
ssh-keygen -t rsa1 -f ssh_host_key -N ""
时,始终不成功,未解决。
8-19猜测 :经猜测,我认为是我使用的openSSH版本过高,不再支持ssh1的key,也是软件为了安全考虑吧。
现在执行:
/sbin/sshd
就可以正常工作了,可以远程登录ssh,以及使用sftp等工具。注意,这里不能用相对路径,如
../init.d/sshd
,查资料知,ssh担心用户恶意修改出同名文件的程序替换真实的sshd而造成安全问题,要求用户调用ssh必须完整地址。这个配置应该可以从某个地方取消,我还没研究。
另外可以增加启动项,使openssh开机启动。开机启动我是这么做的:
编辑
/etc/rc.d/rc.conf
文件,在其中
cfg_services
项中增加:
sshd network
同时在
cfg_services_r
项中增加对应的相反内容。因为ssh要自动联网,所以我把
network
也一并记在这里。
然后在文件下边增加:
export SYSCFG_IFACE0=y
export INTERFACE0="eth0"
export IPADDR0="192.168.1.33"
export NETMASK0="255.255.255.0"
export BROADCAST0="192.168.1.255"
export GATEWAY0="192.168.1.1"
#export NAMESERVER0="202.102.224.68" #dns
修改对应的参数为你的参数,这样就可以上网了,在
/etc/rc.d/init.d/network
中会自动连接网络。
用户登录配置
需要修改root用户登录权限,这是我遇到的第二个问题,这个问题解决了。
修改sshd_config文件:
~
~/usr/local/openssh/etc
PermitRootLogin yes
然后修改root账户的密码,或者自己创建其他账户并设密码,没有密码的账户默认是不能SSH登录的。即使烧录系统后root是有默认密码的,也需要重新设置密码:
~
另外,由于用Dropbox构建的根文件系统不满足ssh安全标准,所以这时可能还无法登录,会始终提示
WARNING: Your password has expired. You must change your password and login again!
,解决办法是,手动修改
/etc/shadow
文件,如下:
root:......:11851:5:99999:7:5:20000:
sshd:......:11851:5:99999:7:5:20000:
中间省略号的地方是密码,每个机器都不相同,如果我上边的
11851
这块在你的板子上是
0
,就不能通过SSH安全标准,可以试着改成和下边其他账户一样的数字。网上还说将运行有openssh的宿主机的
/etc/passwd
/etc/shadow
group
文件复制到开发板
/etc
目录下,同时将
passwd
中的root行最末尾
/bin/bash
改为
/bin/sh
,也可以解决这个问题。我未尝试,有待验证。
后来遇到一个问题,ssh登录正常,但sftp无法登录,查阅网络资料,后来找到了问题的解决方案。
查看配置文件
sshd_config
:
~
~/usr/local/openssh/etc
找到一条:
Subsystem sftp /usr/libexec/sftp-server
查看路径,发现与我自己的
sftp-server
路径不同,我的路径是
/usr/local/libexec/sftp-server
,可能他这个是正确的吧,修改自己的
sftp-server
到配置文件中的路径或者修改配置文件中的路径到自己这个文件的路径,都可以解决这个问题。
登录方式
在客户端输入:
ssh root@192.168.1.32
登录,root为用户名,后接ssh服务器ip地址。
问题
- 配置密钥对
ssh-keygen -t rsa1 -f ssh_host_key -N ""
时始终不成功,提示:Saving key "ssh_host_key" failed: unknown or unsupported key type
,但配置其他几个key都成功了。未解决。 - 当登录SSH时,提示
WARNING: Your password has expired. You must change your pasword and login again!
。已解决,解决方案如上。 - 可以登录ssh,但无法登录sftp,提示
connect close
。问题已解决,解决方案如上。
参考文章
-
i.MX6 Openssh移植与测试
http://jingyan.eeboard.com/article/71120
-
将OpenSSH Server 移植到ARM Linux成功http://blog.csdn.net/david_xtd/article/details/11734225
-
移植openssh至arm9嵌入式开发板及常见错误
http://blog.csdn.net/evenness/article/details/16881975
-
OpenSSH移植到ARM Platform–特指启动SSHD服务
http://www.2cto.com/os/201302/188376.html
附件
#!/bin/sh
Exitcode=0
Sshd="/sbin/sshd"
Keygen="/usr/local/openssh/bin/ssh-keygen"
Rsa1key="/usr/local/openssh/etc/ssh_host_key"
Rsakey="/usr/local/openssh/etc/ssh_host_rsa_key"
Dsakey="/usr/local/openssh/etc/ssh_host_dsa_key"
Ecdsakey="/usr/local/openssh/etc/ssh_host_ecdsa_key"
Ed25519key="/usr/local/openssh/etc/ssh_host_ed25519_key"
func_rsa1_keygen()
{
if [ ! -s $Rsa1key ]
then
echo "generating ssh1 rsa host key..."
if $Keygen -q -t rsa1 -f $Rsa1key -N "" > /dev/null 2>&1
then
/bin/chmod 600 $Rsa1key
/bin/chmod 644 $Rsa1key.pub
echo "ssh1 rsa host key done"
else
echo "failed to generate ssh1 rsa host key"
fi
fi
}
func_rsa_keygen()
{
if [ ! -s $Rsakey ]
then
echo "generating ssh2 rsa host key..."
if $Keygen -q -t rsa -f $Rsakey -N "" > /dev/null 2>&1
then
/bin/chmod 600 $Rsakey
/bin/chmod 644 $Rsakey.pub
echo "ssh2 rsa host key done"
else
echo "failed to generate ssh2 rsa host key"
fi
fi
}
func_dsa_keygen()
{
if [ ! -s $Dsakey ]
then
echo "generating ssh2 dsa host key..."
if $Keygen -q -t dsa -f $Dsakey -N "" > /dev/null 2>&1
then
/bin/chmod 600 $Dsakey
/bin/chmod 644 $Dsakey.pub
echo "ssh2 dsa host key done"
else
echo "failed to generate ssh2 dsa host key"
fi
fi
}
func_ecdsa_keygen()
{
if [ ! -s $Ecdsakey ]
then
echo "generating ssh2 ecdsa host key..."
if $Keygen -q -t ecdsa -f $Ecdsakey -N "" > /dev/null 2>&1
then
/bin/chmod 600 $Ecdsakey
/bin/chmod 644 $Ecdsakey.pub
echo "ssh2 ecdsa host key done"
else
echo "failed to generate ssh2 ecdsa host key"
fi
fi
}
func_ed25519_keygen()
{
if [ ! -s $Ed25519key ]
then
echo "generating ssh2 ed25519 host key..."
if $Keygen -q -t ed25519 -f $Ed25519key -N "" > /dev/null 2>&1
then
/bin/chmod 600 $Ed25519key
/bin/chmod 644 $Ed25519key.pub
echo "ssh2 ed25519 host key done"
else
echo "failed to generate ssh2 ed25519 host key"
fi
fi
}
case "$1" in
start)
echo "sshd create keys:"
func_rsa_keygen
func_dsa_keygen
func_ecdsa_keygen
func_ed25519_keygen
echo "starting sshd:"
$Sshd
Exitcode=$?
;;
stop)
echo "stopping sshd:"
/bin/killall $Sshd
Exitcode=$?
;;
restart)
echo "restarting sshd:"
/bin/killall $Sshd
$Sshd
Exitcode=$?
;;
*)
echo "Usage: sshd {start|stop|restart}"
Exitcode=1
esac
exit $Exitcode