#!/bin/bash 
# 全宇宙最强SSH加固脚本（增加PAM检测）
 
# ... [保持原有变量和函数定义不变，直到harden_ssh_config函数] ...
 
# 加固SSH配置 
harden_ssh_config() {
    local config_file="/etc/ssh/sshd_config"
    
    log "INFO" "开始加固SSH配置..."
    
    # 新增PAM检测与配置 
    if [ -d "/etc/pam.d" ]; then 
        log "INFO" "检测到PAM配置目录，开始加固PAM设置"
        
        # 备份原始PAM配置 
        local pam_file="/etc/pam.d/sshd"
        if [ -f "$pam_file" ]; then 
            cp "$pam_file" "${pam_file}.bak_$(date +%Y%m%d_%H%M%S)"
            log "INFO" "已备份PAM配置文件: ${pam_file}.bak"
        fi 
        
        # 写入加固后的PAM配置 
        cat > "$pam_file" <<'EOF'
# SSH终极加固PAM配置 
auth       required     pam_env.so  
auth       sufficient   pam_publickey.so  
auth       required     pam_deny.so  
account    required     pam_nologin.so  
account    required     pam_unix.so  
password   requisite    pam_deny.so  
session    required     pam_selinux.so  close 
session    required     pam_loginuid.so  
session    required     pam_unix.so  
EOF 
        
        # Alpine系统特殊处理 
        if [ "$OS" = "alpine" ]; then 
            sed -i '/pam_deny.so/d'  "$pam_file"
            log "WARN" "Alpine系统特殊处理：保留基础PAM认证"
        fi 
        
        log "INFO" "PAM配置加固完成"
    else 
        log "INFO" "未检测到PAM配置目录，跳过PAM加固"
    fi 
 
    # 以下是原有SSH配置加固逻辑（保持不变）
    # 禁用root密码登录，允许 root 使用公钥登录 
    sed -i 's/^#\?PermitRootLogin.*/PermitRootLogin prohibit-password/' "$config_file"
    # 禁用密码登录 
    sed -i 's/^[# ]*UsePAM.*/UsePAM no/' "$config_file"
    # 禁用密码认证 
    sed -i 's/^#\?PasswordAuthentication.*/PasswordAuthentication no/' "$config_file"
    log "INFO" "已禁用密码认证，仅允许密钥认证"
    
    # 禁用空密码 
    sed -i 's/^#\?PermitEmptyPasswords.*/PermitEmptyPasswords no/' "$config_file"
    log "INFO" "已禁用空密码"
    
    # 禁用X11转发 
    sed -i 's/^#\?X11Forwarding.*/X11Forwarding no/' "$config_file"
    log "INFO" "已禁用X11转发"
    
    # 确保启用了公钥认证 
    if ! grep -q "^PubkeyAuthentication" "$config_file"; then 
        echo "PubkeyAuthentication yes" >> "$config_file"
        log "INFO" "已启用公钥认证"
    else 
        sed -i 's/^#\?PubkeyAuthentication.*/PubkeyAuthentication yes/' "$config_file"
        log "INFO" "已确保公钥认证已启用"
    fi 
    
    # 指定公钥文件位置 
    if ! grep -q "^AuthorizedKeysFile" "$config_file"; then 
        echo "AuthorizedKeysFile .ssh/authorized_keys" >> "$config_file"
        log "INFO" "已设置公钥文件位置"
    fi 
    
    log "INFO" "SSH配置加固完成"
    echo -e "${GREEN}SSH配置加固完成${NC}"
}
# 管理服务函数 
manage_service() {
    local action="$1"
    local service_name="sshd"
    
    case "$SERVICE_MANAGER" in 
        "systemd")
            log "INFO" "使用systemctl $action $service_name"
            systemctl "$action" "$service_name" || return 1 
            ;;
        "openrc")
            log "INFO" "使用rc-service $action $service_name"
            rc-service "$service_name" "$action" || return 1 
            
            # 对于enable操作，使用rc-update 
            if [ "$action" = "enable" ]; then 
                log "INFO" "使用rc-update add $service_name"
                rc-update add "$service_name" || return 1 
            fi 
            ;;
        "sysvinit")
            log "INFO" "使用service $service_name $action"
            service "$service_name" "$action" || return 1 
            
            # 对于enable操作，尝试使用chkconfig或update-rc.d 
            if [ "$action" = "enable" ]; then 
                if check_command "chkconfig"; then 
                    log "INFO" "使用chkconfig启用$service_name"
                    chkconfig "$service_name" on || return 1 
                elif check_command "update-rc.d"; then 
                    log "INFO" "使用update-rc.d启用$service_name"
                    update-rc.d "$service_name" enable || return 1 
                else 
                    log "WARNING" "无法确定如何启用$service_name服务，可能需要手动配置"
                fi 
            fi 
            ;;
        *)
            log "ERROR" "不支持的服务管理系统: $SERVICE_MANAGER"
            return 1 
            ;;
    esac 
    
    return 0 
}
 
# 重启SSH服务 
restart_ssh_service() {
    log "INFO" "准备重启SSH服务..."
    
    # 停止服务 
    if ! manage_service "stop"; then 
        handle_error "6" "停止SSH服务失败"
    fi 
    
    # 启动服务 
    if ! manage_service "start"; then 
        handle_error "6" "启动SSH服务失败"
    fi 
    
    # 启用服务开机自启 
    if ! manage_service "enable"; then 
        log "WARNING" "启用SSH服务开机自启失败，可能需要手动配置"
    else 
        log "INFO" "SSH服务已设置为开机自启"
    fi 
    
    # 检查服务状态 
    log "INFO" "检查SSH服务状态..."
    if [ "$SERVICE_MANAGER" = "systemd" ]; then 
        if ! systemctl is-active --quiet sshd; then 
            handle_error "6" "SSH服务未成功启动"
        fi 
        log "INFO" "SSH服务状态: $(systemctl is-active sshd)"
    elif [ "$SERVICE_MANAGER" = "openrc" ]; then 
        if ! rc-service sshd status | grep -q "started"; then 
            handle_error "6" "SSH服务未成功启动"
        fi 
        log "INFO" "SSH服务状态: running"
    else 
        log "INFO" "无法自动验证服务状态，请手动检查"
    fi 
    
    log "INFO" "SSH服务重启完成"
    echo -e "${GREEN}SSH服务重启完成${NC}"
    
    # 显示SSH配置验证信息 
    log "INFO" "验证SSH配置:"
    if check_command "sshd"; then 
        sshd -t 2>&1 | while read -r line; do 
            log "INFO" "  $line"
        done 
        if [ $? -eq 0 ]; then 
            log "INFO" "SSH配置验证通过"
        else 
            log "WARNING" "SSH配置验证失败，可能存在配置错误"
        fi 
    else 
        log "WARNING" "无法验证SSH配置，未找到sshd命令"
    fi 
}
 
# 显示最终配置 
display_final_config() {
    local config_file="/etc/ssh/sshd_config"
    log "INFO" "显示最终SSH配置..."
    
    echo -e "${GREEN}\n===== 最终SSH配置 (/etc/ssh/sshd_config) ====${NC}"
    
    # 显示配置文件内容并添加中文注释 
    grep -v '^#\|^$' "$config_file" | while read -r line; do 
        case "$line" in 
            "PermitRootLogin no")
                echo -e "${GREEN}$line${NC}    # 禁用root用户直接登录"
                ;;
            "PermitRootLogin yes")
                echo -e "${YELLOW}$line${NC}    # 在Alpine上允许root登录"
                ;;
            "PasswordAuthentication no")
                echo -e "${GREEN}$line${NC}    # 禁用密码认证，仅使用密钥认证"
                ;;
            "PermitEmptyPasswords no")
                echo -e "${GREEN}$line${NC}    # 禁用空密码"
                ;;
            "X11Forwarding no")
                echo -e "${GREEN}$line${NC}    # 禁用X11转发"
                ;;
            "PubkeyAuthentication yes")
                echo -e "${GREEN}$line${NC}    # 启用公钥认证"
                ;;
            "AuthorizedKeysFile .ssh/authorized_keys")
                echo -e "${GREEN}$line${NC}    # 指定公钥文件位置"
                ;;
            *)
                echo -e "${GREEN}$line${NC}"
                ;;
        esac 
    done 
    
    echo -e "${GREEN}=========================================${NC}"
    
    # 显示关键目录和文件权限 
    echo -e "${GREEN}\n===== SSH相关目录和文件权限 ====${NC}"
    echo -e "${GREEN}/root/.ssh 目录权限: $(stat -c %a /root/.ssh)${NC}"
    if [ -f "/root/.ssh/authorized_keys" ]; then 
        echo -e "${GREEN}/root/.ssh/authorized_keys 文件权限: $(stat -c %a /root/.ssh/authorized_keys)${NC}"
    else 
        echo -e "${RED}/root/.ssh/authorized_keys 文件不存在${NC}"
    fi 
    echo -e "${GREEN}/etc/ssh/sshd_config 文件权限: $(stat -c %a /etc/ssh/sshd_config)${NC}"
    echo -e "${GREEN}=========================================${NC}"
}
 
# 主函数 
main() {
    echo -e "${GREEN}===== SSH加固脚本开始执行 ====${NC}"
    log "INFO" "===== SSH加固脚本开始执行 ====" 
    
    # 检查是否为root用户 
    if [ "$(id -u)" -ne 0 ]; then 
        handle_error "0" "请使用root用户运行此脚本"
    fi 
    
    # 步骤1: 检测操作系统 
    detect_os 
    
    # 步骤2: 安装依赖 
    install_dependencies 
    
    # 步骤3: 备份SSH配置 
    backup_ssh_config 
    
    # 步骤4: 下载公钥 
    download_public_key 
    
    # 步骤5: 加固SSH配置 
    harden_ssh_config 
    
    # 步骤6: 重启SSH服务 
    restart_ssh_service 
    
    # 步骤7: 显示最终配置 
    display_final_config 
    
    log "INFO" "===== SSH加固脚本执行完成 ====" 
    echo -e "${GREEN}===== SSH加固脚本执行完成 ====${NC}"
    echo -e "${GREEN}详细日志已保存到: $LOG_FILE${NC}"
}
 
# 执行主函数 
main 