Linux restricts user permissions, JSch, ChannelSftp, ChannelExec, java.util.InterruptedException, /etc/ssh/sshd_config, setfacl

Problem background:

Other systems need to get files on the server when requesting my interface, but I don’t want to give them to users with more permissions.

So I want to create a new user sftpuser on Linux. This user can only download files from the directory and subdirectories I provided, and cannot perform other operations, such as logging in, uploading, modifying files, etc.

User relationship:

I need three users in total.

Because the server where my jar package is located and the file server are separate.

The files generated by the jar package interface are first generated to the local /sftp/files/, and then uploaded to the file server through jsch and channelsftp, and then the local temporary files are deleted.

Two file server users and one server user where the jar package is located.

The user jaruser of the server where the jar package is located needs /sftp permissions.

chown -R jaruser:jaruser /sftp

A file server user fileuser requires /sftp permissions. Used to create directories and upload files through jsch, channelsftp. This user can have more permissions and be more normal.

There is also a file server user that I want to provide to other systems, sftpuser. This user can only download files from the directory and subdirectories I provide, and cannot perform other operations, such as logging in, uploading, modifying files, etc.

Switch to root user

Create new user

useradd sftpuser
passwd sftpuser
# Disable sftpuser login.
# This can be executed now or later. If you execute it at the end, you can log in to test whether the setfacl command works. Test cd, ls, etc.
usermod -s /sbin/nologin sftpuser
mkdir -p /sftp/files/
# This file can be created anywhere, it will not affect it, it is just for running a script.
vim batchACL.sh

batchACL.sh

#!/bin/bash

# Traverse all directories under the root directory, but exclude /sftp and / directories
directories=($(find / -maxdepth 1 -type d ! -wholename "/sftp" ! -wholename "/" -exec echo {<!-- -->} \;))

# Set ACL entries
for dir in "${directories[@]}"; do
  setfacl -m u:sftpuser:- "$dir"
done
chmod 700 batchACL.sh
./batchACL.sh

I configured it both on my computer’s virtual machine and on the server. The only difference is that using jsch, you can connect from your own computer, but not from the server.

Java code reports error,

com.jcraft.jsch.JSchException: java.io.IOException: Pipe closed
Caused by: java.io.IOException:Pipe closed

At this time, you need to configure /etc/ssh/sshd_config

vim /etc/ssh/sshd_config

Whether PasswordAuthentication is set or not has no effect.

Subsystem sftp internal-sftp
Match User sftpuser

systemctl restart sshd
# User who starts the jar package that generates files (I haven’t tested this, but it seems that you don’t need chown, and you can generate files in this directory without chown)
chown -R jaruser:jaruser /sftp
#Use jsch, channelsftp to create directories and upload files (this must be chown)
chown -R fileuser:fileuser /sftp

Tracking pit:

1. There are many people on the Internet talking about setting /etc/ssh/sshd_config. I have tried countless times, but I can’t restrict login at all. I can also cd to other directories. The summary is that it doesn’t work! ! ! ! ! ! !

The Linux command setfacl must be simple and crude.

For the use of this command, please refer to: setfacl linux command online Chinese manual (51yip.com)

setfacl command – Set file ACL policy rules – Linux command list (manual) (linuxcool.com)

2. What a huge pit! ! ! ! ! ! !

If you hit a breakpoint in jsch or channel-related code, and the code reports an error java.util.InterruptedException, you can just cancel the breakpoints or not debug.

It should be related to the timeout setting. I can’t remember clearly. I seem to have set session.connect(10000); and channel.connect(10000); to a relatively large value so that I can debug without reporting errors. This is 10 seconds.

3. This is a big pitfall. It does not affect user permissions. I don’t quite understand what this file does, but changing this file will not help my needs.

vim /etc/sudoers

Some other problems encountered during the pitfall process.

1. If you do not want to prohibit the sftpuser user from logging in first, and see if the cd cannot reach other directories, the batchACL.sh script can change the value of directories.

#!/bin/bash

# Traverse all directories under the root directory, but exclude /D and /directory /lib64. If not excluded, an error will be reported.
# [root@localhost ~]# su sftpuser
# su: failed to execute /bin/bash: Permission denied
directories=($(find / -maxdepth 1 -type d ! -wholename "/sftp" ! -wholename "/" ! -wholename "/bin" ! -wholename "/lib64" ! - wholename "/home" -exec echo {<!-- -->} \;))

# Set ACL entries
for dir in "${directories[@]}"; do
  setfacl -m u:sftpuser:- "$dir"
done

2. Some commands involved in testing the setfacl command

# Set sftpuser pair/file acl rules
setfacl -m u:sftpuser:- /
# This -R must be at the front to clear the sftpuser user and the /file acl rule
setfacl -R -x u:sftpuser /
# Clear all acl
setfacl -b sftpuser

3. This is a screenshot when testing with jsch and channelexec. This is very clear. It means that the service only allows sftp connections. Why? Because I configured ForceCommand internal-sftp.

4. Some codes for testing.

import com.jcraft.jsch.*;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;

/**
 * <dependency>
 * <groupId>com.jcraft</groupId>
 * <artifactId>jsch</artifactId>
 * <version>0.1.55</version>
 * </dependency>
 * session.connect();, channel.connect(); It is best to set the timeout, otherwise the default is to wait indefinitely.
 * Just add a number session.connect(1000);, channel.connect(1000);, the specific size depends on the actual situation.
 */
public class SftpDemo {<!-- -->
    public static void main(String[] args) throws JSchException, SftpException, IOException {<!-- -->
        String host = "192.168.1.200";
        int port = 22;
        String username = "sftpuser";
        String password = "sftpuser";

        JSch jsch = new JSch();
        Session session = jsch.getSession(username, host, port);
        session.setPassword(password);
        // If this is not set, an error will be reported. The reason is not clear. If you are interested, you can study it.
        session.setConfig("StrictHostKeyChecking", "no");
        session.connect();

        //Open a channel
        Channel channel = session.openChannel("exec");
        // According to; split, executed in sequence.
        String cmd = "cd /sftp;mkdir 3.json;";
        ((ChannelExec) channel).setCommand(cmd);
        InputStream in = channel.getInputStream();
        channel.connect();

        //Read command output
        byte[] buffer = new byte[1024];
        int bytesRead;
        StringBuilder result = new StringBuilder();
        while ((bytesRead = in.read(buffer)) > 0) {<!-- -->
            result.append(new String(buffer, 0, bytesRead));
        }

        // Close channel and session
        channel.disconnect();
        session.disconnect();
        //Print command output
        System.out.println("Command output:\\
" + result);


        /*
        ChannelSftp channelSftp = (ChannelSftp) session.openChannel("sftp");
        channelSftp.connect();

        String remoteFilePath = "/sftp/upload/1.txt";
// String remoteFilePath2 = "/opt/software/2.txt";
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        channelSftp.get(remoteFilePath, byteArrayOutputStream);
// channelSftp.get(remoteFilePath2, byteArrayOutputStream);

        String fileContent = new String(byteArrayOutputStream.toByteArray(), StandardCharsets.UTF_8);
        System.out.println("File content:\\
" + fileContent);

        channelSftp.disconnect();
        session.disconnect();

         */
    }

}

5. Various commands.

# Monitor user creation, deletion, connection, etc.
tailf /var/log/secure

[root@localhost ~]# getent passwd sftpuser
sftpuser:x:1004:1004::/home/sftpuser:/bin/bash
[root@localhost ~]# grep sftpuser /etc/passwd
sftpuser:x:1004:1004::/home/sftpuser:/bin/bash
[root@localhost home]# passwd -u sftpuser
Unlocking password for user sftpuser.
passwd: Success

6. In Linux, when we use the mkdir -p /A/B/C/ command to create a directory, if the directory /A/B/C/ already exists, It will not have any bad impact on existing directories and files. This is because the mkdir command ignores existing directories by default.