一. 基礎環境准備
操作系統:Ubuntu16.04Server
先
sudo apt-get install vim openssh-server
便於后續上傳源碼以及調試。
看一下現在openssh的版本:
zjd@ubuntu:~$ ssh -V OpenSSH_7.2p2 Ubuntu-4ubuntu2.6, OpenSSL 1.0.2g 1 Mar 2016
安裝編譯所需要的庫:
zjd@ubuntu:~$ sudo apt-get install build-essential
二. 源碼下載
從https://cdn.openbsd.org/pub/OpenBSD/OpenSSH/portable/下載最新的openssh-7.9p1.tar.gz;
從http://www.zlib.net/下載最新的zlib-1.2.11.tar.gz;
從https://www.openssl.org/source/下載最新的openssl-1.1.1a.tar.gz。
/home/zjd/下新建mySSH目錄,然后將這三個壓縮包上傳上去后用tar分別解壓:
zjd@ubuntu:~/mySSH$ tar -zxvf zlib-1.2.11.tar.gz
。。。
zjd@ubuntu:~/mySSH$ ll total 10312 drwxrwxrwx 5 root root 4096 Dec 17 16:41 ./ drwxr-xr-x 4 root root 4096 Dec 17 16:27 ../ drwxr-xr-x 5 zjd zjd 12288 Oct 18 18:06 openssh-7.9p1/
-rw-rw-r-- 1 zjd zjd 1565384 Dec 17 16:39 openssh-7.9p1.tar.gz drwxr-xr-x 19 zjd zjd 4096 Nov 20 05:35 openssl-1.1.1a/
-rw-rw-r-- 1 zjd zjd 8350547 Dec 17 16:39 openssl-1.1.1a.tar.gz drwxr-xr-x 14 zjd zjd 4096 Jan 15 2017 zlib-1.2.11/
-rw-rw-r-- 1 zjd zjd 607698 Dec 17 16:39 zlib-1.2.11.tar.gz
三. 編譯安裝
1. zlib
進文件夾后直接配置編譯安裝:
zjd@ubuntu:~/mySSH/zlib-1.2.11$ ./configure --prefix=/usr/local zjd@ubuntu:~/mySSH/zlib-1.2.11$ make zjd@ubuntu:~/mySSH/zlib-1.2.11$ sudo make install
2. openssl
注意要先卸載舊版本:
zjd@ubuntu: ~/mySSH/openssl-1.1.1a$ sudo apt-get purge openssl
刪除舊配置文件:
zjd@ubuntu: ~/mySSH/openssl-1.1.1a$ rm -rf /etc/ssl
然后配置編譯安裝新版本:
zjd@ubuntu: ~/mySSH/openssl-1.1.1a$ ./config --prefix=/usr/local --openssldir=/usr/local/ssl zjd@ubuntu: ~/mySSH/openssl-1.1.1a$ make zjd@ubuntu: ~/mySSH/openssl-1.1.1a$ sudo make install zjd@ubuntu: ~/mySSH/openssl-1.1.1a$ ./config shared --prefix=/usr/local --openssldir=/usr/local/ssl zjd@ubuntu: ~/mySSH/openssl-1.1.1a$ make clean zjd@ubuntu: ~/mySSH/openssl-1.1.1a$ make zjd@ubuntu: ~/mySSH/openssl-1.1.1a$ sudo make install
其中:prefix 是安裝目錄,openssldir 是配置文件目錄,另外建議安裝兩次,shared 作用是生成動態連接庫。
最后,因為是非root用戶安裝,因此需要增加兩條軟連接:
zjd@ubuntu:~/mySSH/openssl-1.1.1a$ sudo ln -s /usr/local/lib/libssl.so.1.1 /usr/lib/libssl.so.1.1 zjd@ubuntu:~/mySSH/openssl-1.1.1a$ sudo ln -s /usr/local/lib/libcrypto.so.1.1 /usr/lib/libcrypto.so.1.1
OK,現在看一下openssl的版本:
zjd@ubuntu:~/mySSH/openssl-1.1.1a$ openssl version OpenSSL 1.1.1a 20 Nov 2018
3. openssh
zjd@ubuntu:~/mySSH/openssh-7.9p1$ ./configure -prefix=/usr/local -sysconfdir=/etc/ssh -with-ssl-dir=/usr/local/ssl zjd@ubuntu:~/mySSH/openssh-7.9p1$ make zjd@ubuntu:~/mySSH/openssh-7.9p1$ sudo make install
安裝完重啟服務:
zjd@ubuntu:~/mySSH/openssh-7.9p1$ sudo systemctl restart sshd.service
現在再看一下ssh的版本:
zjd@ubuntu:~/mySSH/openssh-7.9p1$ ssh -V OpenSSH_7.9p1, OpenSSL 1.1.1a 20 Nov 2018
四. 修改openssh源碼
當修改了openssh源碼后,為了不影響系統已啟動的ssh服務的運行,應該重新配置編譯輸出路徑,然后停掉系統已啟動的ssh服務,啟動新編譯的sshd。過程如下:
zjd@ubuntu:~/mySSH/openssh-7.9p1$ sudo vim session.c zjd@ubuntu:~/mySSH/openssh-7.9p1$ make clean zjd@ubuntu:~/mySSH/openssh-7.9p1$ ./configure -prefix=/usr/local/myssh -sysconfdir=/etc/ssh -with-ssl-dir=/usr/local/ssl zjd@ubuntu:~/mySSH/openssh-7.9p1$ make zjd@ubuntu:~/mySSH/openssh-7.9p1$ sudo make install zjd@ubuntu:~/mySSH/openssh-7.9p1$ sudo /etc/init.d/ssh stop zjd@ubuntu:~/mySSH/openssh-7.9p1$ sudo /usr/local/myssh/sbin/sshd
再次繼續修改時,最后兩行停止和啟動服務的操作就不用執行了。
如果重啟了系統,則最后兩步要重新執行一下。當然,也可以寫個開機啟動腳本,這樣系統啟動時就自動執行最后兩行了,方法如下:
在/etc/init.d/目錄下新建一個腳本文件startmyssh.sh,並賦予運行權限:
zjd@ubuntu:/etc/init.d$ sudo chmod 755 startmyssh.sh
vim編輯腳本內容為:
#!/bin/bash
### BEGIN INIT INFO
# Provides: Zhang Jidong
# Required-Start: $local_fs
# Required-Stop: $local_fs
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: sshd service
# Description: mysshd service
### END INIT INFO
sudo /etc/init.d/ssh stop sudo /usr/local/myssh/sbin/sshd exit 0
注意前面的注釋部分格式一定要一樣,否則會有各種警告;
最后添加啟動調用:
zjd@ubuntu:/etc/init.d$ sudo update-rc.d startmyssh.sh defaults 90
好了,現在可以重啟試試了!
五. openssh日志
openssh的配置文件位於:
zjd@ubuntu:/etc/ssh$ sudo vim sshd_config
# Logging
SyslogFacility AUTH LogLevel INFO
詳細定義位於log.h,如下:
/* Supported syslog facilities and levels. */ typedef enum { SYSLOG_FACILITY_DAEMON, SYSLOG_FACILITY_USER, SYSLOG_FACILITY_AUTH, #ifdef LOG_AUTHPRIV
SYSLOG_FACILITY_AUTHPRIV, #endif
SYSLOG_FACILITY_LOCAL0, SYSLOG_FACILITY_LOCAL1, SYSLOG_FACILITY_LOCAL2, SYSLOG_FACILITY_LOCAL3, SYSLOG_FACILITY_LOCAL4, SYSLOG_FACILITY_LOCAL5, SYSLOG_FACILITY_LOCAL6, SYSLOG_FACILITY_LOCAL7, SYSLOG_FACILITY_NOT_SET = -1 } SyslogFacility; typedef enum { SYSLOG_LEVEL_QUIET, SYSLOG_LEVEL_FATAL, SYSLOG_LEVEL_ERROR, SYSLOG_LEVEL_INFO, SYSLOG_LEVEL_VERBOSE, SYSLOG_LEVEL_DEBUG1, SYSLOG_LEVEL_DEBUG2, SYSLOG_LEVEL_DEBUG3, SYSLOG_LEVEL_NOT_SET = -1 } LogLevel;
SyslogFacility配置為AUTH,則日志會輸出到/var/log/auth.log
六. sftp日志
sftp是openssh根據功能需要啟動的子進程,缺省是關閉了日志的。打開方法為:
sudo vim /etc/ssh/sshd_config
在Subsystem所在行最后增加 -l DEBUG3,如下:
Subsystem sftp /usr/libexec/openssh/sftp-server -l DEBUG3
將sftp的日志單獨存放:
sudo vim /etc/rsyslog.conf
最后面增加如下內容:
# Log sftp-server in a separate file
:programname, isequal, "sftp-server" /var/log/sftp.log
現在就可以重啟sshd服務和rsyslog服務來生效了:
sudo systemctl restart rsyslog.service
sudo systemctl restart sshd.service
看:
zjd@ubuntu:/var/log$ ll -t total 1532
-rw-r----- 1 syslog adm 379366 Dec 20 04:58 syslog -rw-r----- 1 syslog adm 61409 Dec 20 04:53 auth.log -rw-r----- 1 syslog adm 6460 Dec 20 04:41 sftp.log drwxrwxr-x 7 root syslog 4096 Dec 20 04:40 ./ drwxr-xr-x 12 root root 4096 Dec 20 04:31 ../
-rw-r--r-- 1 root root 568865 Dec 20 04:25 dpkg.log -rw-rw-r-- 1 root utmp 292292 Dec 20 04:22 lastlog -rw-rw-r-- 1 root utmp 5376 Dec 20 04:22 wtmp -rw-r----- 1 syslog adm 348026 Dec 20 04:22 kern.log
……
建議設置logrotate避免日志過大。方法是sudo vim創建/etc/logrotate.d/sftp文件,輸入下面內容並保存:
/var/log/sftp.log { postrotate /bin/kill -HUP `cat /var/run/syslogd.pid 2> /dev/null` 2> /dev/null || true endscript }
如果此時通過FileZilla客戶端訪問openssh-server,查看文件列表以及上傳下載等操作,可以通過日志發現這些操作的實現都在sftp-server.c中。
七. 限制sftp用戶只能訪問指定目錄
添加用戶test1:
zjd@ubuntu:/home$ sudo useradd test1
為test1設置密碼:
zjd@ubuntu:/home$ sudo passwd test1
編輯
sudo vim /etc/ssh/sshd_config
將已有的Subsystem sftp /usr/lib/openssh/sftp-server -l DEBUG3改為:
Subsystem sftp internal-sftp -l DEBUG3
並在最后為test1增加如下配置:
Match User test1 ChrootDirectory /home/test1 X11Forwarding no AllowTcpForwarding no ForceCommand internal-sftp -l DEBUG3
創建好目錄:
zjd@ubuntu:/home# sudo mkdir test1
權限設置:
zjd@ubuntu:/home$ sudo chown root:root /home/test1 zjd@ubuntu:/home$ sudo chmod 755 /home/test1 zjd@ubuntu:/home$ sudo usermod test1 -s /sbin/nologin
現在重啟sshd服務,可以發現已經是只能登錄到/home/test1目錄中了。但此時沒有寫權限,那就繼續如下配置,給test1配置一個可以讀寫的data文件夾:
zjd@ubuntu:/home/test1# sudo mkdir data
zjd@ubuntu:/home/test1# sudo chown test1:test1 /home/test1/data/
zjd@ubuntu:/home/test1# sudo chmod 755 /home/test1/data/
好了,現在用戶通過sftp登錄后,就能看到一個data文件夾,並且在這個data文件夾里面可以進行讀寫操作了。
此時前面加的-l DEBUG3參加(打印sftp.log)無效了,需要再進行如下配置:
/home/test1下新建dev文件夾:
zjd@ubuntu:/home/test1# sudo mkdir dev
編輯sudo vim /etc/rsyslog.conf,最后面新增:
# Create an additional socket for some of the sshd chrooted users.
$AddUnixListenSocket /home/test1/dev/log # Log internal-sftp in a separate file
:programname, isequal, "sftp" /var/log/sftp.log
(如果增加多個用戶,只需重復增加AddUnixListenSocket命令即可。)
編輯
root@ubuntu:/home# vim /etc/selinux/config
新增:
SELINUX=disabled
重啟一下日志服務:
zjd@ubuntu:/home/test1# sudo systemctl restart rsyslog.service
好了,現在重啟系統吧!
此時sftp用戶登錄后看到的是兩個文件夾data和dev,如果自動進入data文件夾,則體驗更好。此時就需要修改sftp-server.c,在函數process_realpath中增加如下
if (strlen(path) == 1 && !strcmp(path, "."))部分的內容:
static void process_realpath(u_int32_t id) { char resolvedname[PATH_MAX]; char *path; int r; if ((r = sshbuf_get_cstring(iqueue, &path, NULL)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); if (path[0] == '\0') { free(path); path = xstrdup("."); } debug3("request %u: realpath", id); verbose("realpath \"%s\"", path); if (strlen(path) == 1 && !strcmp(path, ".")) { logit("======== Change path from '.' to '/data/.'"); free(path); path = xstrdup("/data/."); } if (realpath(path, resolvedname) == NULL) { send_status(id, errno_to_portable(errno)); } else { Stat s; attrib_clear(&s.attrib); s.name = s.long_name = resolvedname; send_names(id, 1, &s); } free(path); }