Samba 文件共享服务

本文合并自:05-Samba服务.md、11-Samba服务.md、1-13-Samba服务部署.md

适用环境:CentOS/RHEL 5/6(Samba 3.x)与 CentOS/RHEL 7(Samba 4.x)。文中凡涉及两个版本操作差异之处,均并列给出并标注适用版本。


一、Samba 概述与原理

1.1 什么是 Samba

Samba 是一套基于 SMB(Server Messages Block,信息服务块)协议 的开源网络文件共享服务,主要用于在 Windows 与 UNIX/Linux 之间共享文件、打印机等资源。

Samba 最初由 DEC 开始开发,用于在不同的 Unix 机器间进行资源共享,早期采用 UDP 协议。后来基于 TCP 重新开发后,效率有了很大提高,它使用的协议是 SMB。微软不愿意交 License 费,在 Windows 系统中对该协议重新进行了实现。既然 Samba 和 Windows 中的「网络邻居」都使用 SMB 协议,那么 Samba 自然主要用于在 Windows 和 Unix 之间共享资源,资源包括文件、打印机等等。

项目 说明
协议 SMB(历史上基于 UDP,现代版本基于 TCP)
主要用途 Windows 与 Linux/Unix 之间共享文件、打印机
与 NFS 对比 Samba 配置更灵活,NFS 配置更简单;NFS 更适合纯 Unix/Linux 环境

1.2 Samba 服务的特点

  1. 支持更详细的访问控制(可对同一目录下的不同用户设置不同权限);
  2. 可跨平台共享文件(Linux↔Windows、Linux↔Linux);
  3. 对初级用户友好,Windows 端可直接「映射网络驱动器」使用。

典型使用场景:

  • 办公网内为 Windows 桌面用户提供部门文件服务器;
  • Linux 服务器把日志、软件包目录共享给 Windows 运维终端;
  • 多用户协作目录,要求「能读别人的、只能删自己的」这类精细权限;
  • 网络打印机共享。

1.3 SMB/CIFS 协议与版本演进

SMB 协议在发展过程中出现了 CIFS(Common Internet File System)这一名称,它本质上是 SMB 1.0 的一个方言/扩展,Linux 挂载时使用的文件系统类型名 cifs 即源自此。

协议版本 说明与适用性
SMB1 / CIFS 最早的版本,Windows XP / Windows Server 2003 及部分老旧设备(老式打印机、NAS、扫描仪)使用。存在严重安全问题(明文/弱认证、无消息签名强制、易受中间人与 WannaCry 类蠕虫攻击),现代系统默认禁用,应尽量不再启用
SMB2(2.0/2.1) Windows Vista / 7 / Server 2008 起引入,减少了命令往返次数,性能与稳定性大幅提升
SMB3(3.0/3.02/3.1.1) Windows 8 / Server 2012 及以后,支持传输加密、多通道(Multichannel)、持久句柄、SMB Direct 等特性,是目前推荐使用的版本

在 Samba 中通过 [global] 段的 min protocol / max protocol 控制可协商的协议版本;客户端挂载时通过 -o vers= 指定版本。

[global]
    # 禁用不安全的 SMB1,最低要求 SMB2
    min protocol = SMB2
    max protocol = SMB3

注意:禁用 SMB1 后,Windows XP 等老客户端与部分老旧硬件设备将无法连接(详见排错清单)。

1.4 NetBIOS 名称解析与 WINS

Windows 网络中主机之间除了使用 IP,还使用 NetBIOS 名称(长度不超过 15 个字符的计算机名)互相标识。NetBIOS 名称解析有以下几种途径:

  1. 广播:在同一广播域内发送 NetBIOS 名称查询广播包(UDP 137);
  2. lmhosts 静态映射文件:Samba 端为 /etc/samba/lmhosts,写法类似 /etc/hosts;
  3. WINS(Windows Internet Name Service)服务器:集中注册和解析 NetBIOS 名称,可跨网段解析。Samba 可以作为 WINS 服务器或 WINS 客户端:
[global]
    # 让 Samba 自身充当 WINS 服务器
    wins support = yes
    # 或者作为客户端向指定 WINS 服务器注册与查询(两者不可同时启用)
    # wins server = 192.168.0.10
    # 名称解析顺序
    name resolve order = lmhosts wins bcast host

NetBIOS 名称解析由 nmbd 进程负责。如果客户端只通过 IP 地址访问共享,则名称解析并非必需。

1.5 Samba 使用的端口

端口 协议 用途 对应进程
137 UDP NetBIOS 名称服务(名称注册与解析) nmbd
138 UDP NetBIOS 数据报服务(浏览列表、工作组通告) nmbd
139 TCP NetBIOS Session Service,SMB over NetBIOS(旧方式) smbd
445 TCP SMB over TCP(直接承载,现代方式) smbd

RHEL 6 默认环境下实际只监听 TCP 139、445(UDP 137/138 由 nmbd 在启动后监听,若未启动 nmb 则不监听)。

验证监听状态:

netstat -ntlup | grep bd
# tcp  0  0  :::139  :::*  LISTEN  4507/smbd
# tcp  0  0  :::445  :::*  LISTEN  4507/smbd

1.6 Samba 的三个核心进程

守护进程 职责 相关端口
smbd 核心进程。管理共享目录、文件读写与打印服务,负责用户认证、权限判定、SMB 会话处理 TCP 139、445
nmbd 管理工作组(workgroup)、NetBIOS 名称解析与浏览列表(网上邻居中能否被自动发现) UDP 137、138
winbindd 与 Windows 域控制器(NT 域 / AD 域)交互,把域用户和域组映射为 Linux 本地的 UID/GID,实现统一身份认证。仅在加入域环境时需要

关于 smb 与 nmb 服务单元:smb 是提供文件共享的主服务,nmb(nmbd)只负责 NetBIOS 名称解析与「网上邻居」浏览列表。若客户端通过 IP 地址访问(如 smbclient -L //192.168.0.183),仅启动 smb 即可满足需求,日常调试常简写为 systemctl restart smb;只有需要通过 NetBIOS 名称访问或在 Windows 网络中被自动发现时,才必须同时启动 nmb。

1.7 Samba 与 NFS、FTP 适用场景对比

特性 Samba NFS
开发方 DEC 发起 Sun 开发
主要协议 SMB/CIFS NFS
最佳场景 Windows 与 Linux 跨平台共享 Unix/Linux 之间共享
配置复杂度 较高,参数灵活 较低,配置简单
典型效率 与 NFS 接近,通常 NFS 略高 通常略高
权限模型 有独立的用户密码库,可做同目录多用户差异化权限 依赖客户端 UID/GID 映射,权限控制较粗

三种共享服务的横向对比:

对比项 FTP Samba NFS
跨公网 可以直接跨公网 不能直接跨公网,需借助 VPN 一般用于内网
权限控制 较弱,不适合多用户在同一目录做不同权限 权限控制精细,适合同目录多用户不同权限 Linux 到 Linux
跨平台 跨平台 跨平台(Linux↔Windows、Linux↔Linux) Linux↔Linux
客户端易用性 需 FTP 客户端软件 可在 Windows 中映射网络驱动器,对初级用户友好 Linux 挂载

NFS 的配置主要是编辑 /etc/exports 文件,然后运行 exportfs -arv 共享出来,现在 NFS 已经成为 UNIX/Linux 上的标配。从效率来看 NFS 稍微高一些,但差别不是太大;从配置来看 Samba 比较复杂,但复杂有复杂的道理,它让我们能够更灵活地配置。

1.8 客户端访问控制的总流程

无论什么服务,客户端访问一般都要依次经过以下几道关卡,排错时应按此顺序逐层检查:

客户端程序
   |
iptables / firewalld(防火墙)
   |
pam(控制是否可登录)
   |
selinux(程序域能否访问文件/目录类型)
   |
服务参数是否允许(smb.conf)
   |
系统权限 rwx(含 ACL、粘滞位)
   |
服务程序

常用服务的匿名用户身份:

服务 匿名用户
NFS nfsnobody
FTP ftp、anonymous
Samba nobody

二、安装与主配置文件详解

2.1 安装软件包

# 安装 Samba 服务端及常用组件
sudo yum install samba samba-common -y

# 安装 Samba 客户端(用于测试或挂载其他共享)
sudo yum install samba-client -y

也可以一次性安装全部相关包:

yum install samba* -y

RHEL 6.4 以上版本 ISO 自带两个版本的 samba,yum install samba* 可能报冲突,可改用 yum install samba-*。

各包的作用:

软件包 作用
samba 服务端主程序,提供 smbd、nmbd
samba-common 服务端与客户端公用的配置文件与工具(如 testparm)
samba-client 客户端工具,提供 smbclient、smbtar 等
samba-winbind、samba-winbind-clients winbindd 及其客户端,用于对接 NT/AD 域
cifs-utils 提供 mount.cifs,Linux 挂载 SMB 共享的必需包

查看已安装包:

rpm -qa | grep samba
# samba-winbind-3.5.10-125.el6.x86_64
# samba-common-3.5.10-125.el6.x86_64
# samba-winbind-clients-3.5.10-125.el6.x86_64
# samba-client-3.5.10-125.el6.x86_64
# samba-3.5.10-125.el6.x86_64

Samba 完整详细的文档可参考 man 文档:

man smb.conf
# 或 man 5 smb.conf

2.2 目录与文件结构

路径 说明
/etc/samba/smb.conf 主配置文件
/etc/samba/smbusers Samba 用户名与 Linux 用户名的映射表(配合 username map)
/etc/samba/smbpasswd 早期 smbpasswd 后端的密码文件(使用 tdbsam 后端时不再使用)
/etc/samba/lmhosts NetBIOS 名称到 IP 的静态映射文件
/var/lib/samba/ 运行期数据库目录,passdb.tdb(账号库)、secrets.tdb(机器账号与域密钥)、browse.dat 等
/var/log/samba/ 日志目录,log.smbd、log.nmbd、log.<客户端名>
/var/spool/samba/ 打印共享的假脱机目录
/usr/bin/smbclient、smbpasswd、pdbedit、testparm、smbstatus 常用命令

编辑主配置文件:

sudo vim /etc/samba/smb.conf

2.3 smb.conf 的结构

Samba 配置文件由多个「段(section)」组成,段名用方括号括起。[global] 为全局配置,[homes]、[printers] 是两个特殊的内置共享段,其余为自定义共享段:

[global]                                    # 表示这是影响全局的配置
    workgroup = MYGROUP                     # 工作组
    server string = Samba Server Version %v # 服务器描述
    log file = /var/log/samba/log.%m
    max log size = 50
    security = user            # 非常重要的参数:user 代表客户端必须提供用户名和密码(匿名除外)
                              # 值为 share 时不需要密码,下面的配置要做相应改变
    passdb backend = tdbsam    # 使用本地 .tdb 文件保存账号密码
    load printers = yes        # 是否加载打印机
    cups options = raw         # 打印机类型

[homes]                                     # 用户家目录共享(特殊段)
    comment = Home Directories
    browseable = no
    writable = yes

[printers]                                  # 打印机共享(特殊段)
    comment = All Printers
    path = /var/spool/samba
    browseable = no
    guest ok = no
    writable = no
    printable = yes

[software]                                  # 自定义共享段:只读共享示例
    comment         = Shared software        # 自定义描述
    path            = /external/software     # 共享目录
    guest ok        = yes                    # 是否允许匿名访问
    browseable      = yes                    # 是否出现在查询列表中
    writeable       = no                     # 是否可写

[upload]                                    # 自定义共享段:可写共享示例
    comment              = Upload
    path                 = /opt/upload
    guest ok             = no
    browseable           = yes
    writeable            = yes
    valid users          = u1,u2,+g1             # 允许访问的用户和组
    write list           = u1                    # 读写列表
    read list            = u2,+g1                # 只读列表
    create mode          = 0344                  # 控制新建文件的权限
    force create mode    = 0344                  # 控制新建文件的权限
    directory mode       = 0777                  # 控制新建目录的权限
    force directory mode = 0777                  # 控制新建目录的权限
    hosts deny           = all                   # 禁止访问的客户端
    hosts allow          = 192.168.0.0/24 except 192.168.0.222   # 允许访问的客户端

部分资料中出现的 assdb backend = tdbsam 是笔误,正确指令为 passdb backend。

[homes] 段的含义:该段会在用户登录时自动把共享名变为对应用户的家目录。Samba 默认把每个系统用户的家目录共享出去,但前提是该用户已通过 smbpasswd -a 加入 Samba 账号库。若不希望用户访问自己的家目录,把 [homes] 段整体注释即可。

2.4 [global] 全局段常用参数逐项详解

参数 说明
workgroup Windows 工作组(或 NT 域)名称,需与客户端一致才便于在网上邻居中发现
server string 服务器描述信息,%v 为 Samba 版本变量
netbios name 本机在 Windows 网络中显示的 NetBIOS 名称(不超过 15 字符),默认取主机名的第一段
security 安全(工作)模式,取值 user / share / server / domain / ads,详见 2.5
passdb backend 用户密码数据库后端。tdbsam 表示使用本地 TDB 数据库文件 /var/lib/samba/passdb.tdb;历史上还有 smbpasswd(纯文本文件)与 ldapsam(LDAP)
map to guest 认证失败时如何降级为 guest。Never(默认,直接拒绝)、Bad User(用户名不存在则当作 guest,实现匿名共享的关键)、Bad Password(密码错误也当 guest,不安全)、Bad Uid
guest account 匿名访问时映射到的系统账号,默认 nobody
hosts allow 允许访问的客户端列表,可写网段、IP、主机名,支持 EXCEPT 排除
hosts deny 拒绝访问的客户端列表
interfaces 指定 Samba 监听的网络接口或网段,如 interfaces = lo eth0 192.168.0.0/24
bind interfaces only 值为 yes 时仅在 interfaces 列出的接口上监听,用于把服务限制在内网口
log file 日志文件路径,%m 代表客户端 NetBIOS 名,可为每个客户端生成单独日志
max log size 单个日志文件最大大小(单位 KB),超过后轮转,0 表示不限制
log level 日志级别 0~10,数字越大越详细,排错时可临时调到 3
smb ports smbd 监听的端口,默认 445 139
min protocol 允许协商的最低协议版本,如 SMB2,用于禁用不安全的 SMB1
max protocol 允许协商的最高协议版本,如 SMB3
unix charset Linux 服务器端使用的字符集,通常为 UTF-8
dos charset 与老式 Windows/DOS 客户端交互使用的字符集,简体中文环境为 cp936(GBK),用于解决中文文件名乱码
display charset 服务器端显示(如 smbclient 输出)使用的字符集
load printers 是否自动加载 /etc/printcap 中的所有打印机为共享
printing 打印系统类型,如 cups、lprng、bsd
cups options CUPS 打印选项,raw 表示由客户端驱动生成打印数据,服务器不再处理
config file 按变量加载附加配置文件,如 config file = /etc/samba/smb.conf.%U(%U 为登录用户名)
include 包含另一个配置文件,同样支持 %U、%m 等变量
wins support / wins server 充当 WINS 服务器 / 指定 WINS 服务器(互斥)
name resolve order NetBIOS 名称解析顺序,如 lmhosts wins bcast host
username map 用户名映射文件,通常为 /etc/samba/smbusers

中文乱码的典型配置:

[global]
    unix charset = UTF-8
    dos charset = cp936
    display charset = UTF-8

2.5 security 工作模式的演变

模式 说明 适用版本
share 不需要用户名密码,匿名用户模式 Samba 3.x(CentOS 5/6)可用;Samba 4.x 起已废弃,CentOS 7 中不再支持
user 使用 Samba 自己的密码资料库(普通用户模式),需提供用户名和密码,最常用 全版本
server 使用外部主机(另一台 SMB 服务器)的密码,用户信息存放在远程服务器 Samba 3.x,已废弃
domain 加入 NT 域,由域控制器认证 全版本
ads 加入 Active Directory 域,使用 Kerberos 认证 Samba 3.x 起

CentOS 7 / Samba 4 注意:security = share 与 security = server 已被移除。要实现匿名共享,应使用 security = user 搭配 map to guest = Bad User,并在共享段设置 guest ok = yes。

[global]
    security = user
    map to guest = Bad User      # CentOS 7 实现匿名访问的关键
    guest account = nobody

2.6 共享段常用参数逐项详解

参数 说明
comment 共享的描述信息,客户端浏览时显示
path 共享目录的本地绝对路径
browseable 是否在共享(浏览)列表中可见。no 时共享仍可用,只是「隐藏」,知道共享名可直接访问
writable / writeable 是否可写(与 read only 反义)
read only 是否只读(与 writable 反义)
public 是否允许匿名用户登录(与 guest ok 同义)
guest ok 是否允许匿名用户登录(与 public 同义)
guest only 只允许以 guest 身份访问该共享
valid users 指定允许访问的用户/组白名单,组名前加 @ 或 +,如 valid users = u1,u2,@smb
invalid users 拒绝访问的用户/组黑名单,优先级高于 valid users
write list 具有写权限的用户/组列表(即使共享为 read only = yes,列表内用户仍可写)
read list 只有读权限的用户/组列表(与 write list 反义)
admin users 该列表内的用户在此共享中以 root 身份操作,可读写删除任何文件(权限极大,谨慎使用)
create mask / create mode 新建文件的权限掩码(上限),类似 umask 的作用方向相反,直接给出允许的权限位
force create mode 强制新建文件必须具备的权限位(下限)
directory mask / directory mode 新建目录的权限掩码
force directory mode 强制新建目录必须具备的权限位
force user 强制所有访问该共享的用户以指定系统用户身份操作文件
force group 强制所有新建文件的属组为指定组,常用于多用户组协作共享
available no 时该共享被临时禁用(配置保留但不生效)
follow symlinks 是否跟随共享目录内的符号链接,默认 yes
wide links 是否允许跟随指向共享目录之外的符号链接,默认 no(安全考虑)
veto files 完全隐藏且禁止访问的文件模式,以 / 分隔,如 veto files = /*.mp3/*.exe/
delete veto files 删除目录时是否连同被 veto 的文件一起删除
hide files 隐藏(但仍可访问)的文件模式,写法同 veto files
hide dot files 是否把以 . 开头的文件标记为隐藏,默认 yes
inherit permissions 新建文件/目录继承父目录的权限位,会覆盖 create mask 的效果
inherit acls 新建对象继承父目录的 POSIX ACL
printable 该共享是否为打印队列共享(打印共享必须为 yes)
hosts allow / hosts deny 允许/拒绝访问的客户端地址,可写在共享段仅对该共享生效
max connections 该共享允许的最大并发连接数
vfs objects 加载 VFS 模块,如 recycle(回收站)、full_audit(审计)

三对同义/反义参数(务必只写一个,避免冲突):

  • public 与 guest ok(同义);
  • writable / writeable 与 read only(反义);
  • write list 与 read list(反义)。

当反义/同义参数同时出现时,写在后面的参数生效:

[test]
    comment = public for everyone
    path = /test
    browseable = yes
    read only = yes
    writable = yes          # 写在后面,最终结果是可写

create mode 与 force create mode 的区别

两者名字相近但作用方向相反,容易混淆:

参数 性质 作用
create mode 掩码(上限) 客户端请求的权限与该值按位「与」运算,只能去掉多余权限,不会增加权限
force create mode 强制置位(下限) 与结果按位「或」运算,将指定的权限位强制打开,无论客户端是否请求

计算顺序为:最终权限 = (客户端请求权限 & create mode) | force create mode。

例如同时设置 create mode = 0400 与 force create mode = 0400,则新建文件的权限被锁定为 0400(仅属主可读):掩码把组和其他人的权限全部去掉,强制位再保证属主的读权限一定存在。若只写 create mode = 0400,当客户端本身请求 0000 时结果仍是 0000;若只写 force create mode = 0400,客户端请求的其他权限位仍会被保留。directory mode 与 force directory mode 对目录的作用方式完全相同。

权限默认值机制小结:

机制 文件默认权限 目录默认权限
系统 umask 666 - umask 777 - umask
vsftpd anon_umask / local_umask 666 - umask 777 - umask
Samba create mask / directory mask 直接定义为所设值 直接定义为所设值

注意:无论哪种机制,最终权限不一定完全等于配置值(还受父目录、inherit permissions、客户端请求影响),以实际测试结果为准。Samba 默认上传文件权限为 0744,新建目录为 0755。

2.7 访问控制(hosts allow / hosts deny)

访问控制指令可写在 [global] 全局段(对所有共享生效),也可写在单独共享段(仅对该共享生效)。

# 拒绝 10.0.0 网段
hosts deny = 10.0.0.

# 拒绝 10.0.0 网段,但允许 10.0.0.35(allow 优先于 deny)
hosts deny = 10.0.0.
hosts allow = 10.0.0.35

# 拒绝所有,但允许 10.0.0 网段,其中 10.0.0.45 除外
hosts deny = all
hosts allow = 10.0.0. EXCEPT 10.0.0.45

# 也可使用掩码写法
hosts allow = 192.168.0.0/255.255.255.0 except 192.168.0.222
hosts allow = 192.168.0.0/24 except 192.168.0.222

规则:hosts allow 的优先级高于 hosts deny;EXCEPT(或小写 except)用于在允许范围内排除个别地址。

2.8 testparm 语法检查

修改配置文件后,务必先用 testparm 检查语法,再重载服务:

sudo testparm

常用形式:

testparm                      # 检查语法并交互式显示解析后的配置
testparm -s                   # 直接输出解析结果,不等待回车
testparm -v                   # 显示包括默认值在内的全部参数
testparm -s /etc/samba/smb.conf.u1   # 检查指定的配置文件

输出中 Loaded services file OK. 表示语法无误。修改 smb.conf 前建议先备份:

cp /etc/samba/smb.conf /etc/samba/smb.conf.bak

三、用户管理与共享实战

3.1 Samba 账号体系与系统账号的关系

在 security = user 模式下,Samba 用户必须同时满足以下两个条件:

  1. 必须是服务器上的 系统用户(先用 useradd 创建);
  2. 必须使用 smbpasswd -a(或 pdbedit -a)把该用户添加到 Samba 用户数据库 中。

要点说明:

  • Samba 密码库与系统 /etc/shadow 相互独立,Samba 密码可以与系统密码不一致,修改 Samba 密码不会影响系统密码;
  • 默认后端 tdbsam 把账号信息存放在 /var/lib/samba/passdb.tdb;
  • 若用户不需要登录 Linux 系统,可创建为非登录用户:useradd -s /sbin/nologin u1;
  • 删除系统用户后,其 Samba 账号记录不会自动清理,需要 smbpasswd -x 或 pdbedit -x 手工删除。

3.2 smbpasswd 命令

# 添加 Samba 用户(add),会提示两次输入密码
sudo smbpasswd -a u1
# New SMB password:
# Retype new SMB password:
# Added user u1.

# 修改 Samba 用户 u1 的密码
sudo smbpasswd u1

# 删除 Samba 用户
sudo smbpasswd -x u1

# 禁用 Samba 用户(disable)
sudo smbpasswd -d u1

# 启用被禁用的用户(enable)
sudo smbpasswd -e u1

# 普通用户修改自己的 Samba 密码(不加选项、不加用户名)
smbpasswd
选项 作用
-a 添加 Samba 用户(add)
-x 删除 Samba 用户
-d 禁用 Samba 用户(disable)
-e 启用被禁用的用户(enable)
-n 将密码设为空
-s 从标准输入读取密码,便于脚本批量添加

脚本批量添加示例:

(echo "123456"; echo "123456") | smbpasswd -s -a u1

3.3 pdbedit 命令

pdbedit 是 Samba 3.x 起推荐的账号管理工具,功能比 smbpasswd 更全面。

# 列出所有 Samba 用户(List)
sudo pdbedit -L

# 列出所有用户的详细信息(verbose)
sudo pdbedit -Lv

# 列出用户 u1 的详细信息
sudo pdbedit -Lv u1

# 添加用户(会提示输入密码)
sudo pdbedit -a u1

# 删除用户
sudo pdbedit -x u1

# 禁用/启用账号(通过修改账号标志位)
sudo pdbedit -c "[D]" -u u1      # 置 D 标志,禁用
sudo pdbedit -c "[]" -u u1       # 清除标志,启用

# 备份与导入账号库
sudo pdbedit -L -w > /root/samba_users.txt
选项 作用
-L 列出所有 Samba 用户
-v 与 -L 配合,显示详细信息
-a 添加用户
-x 删除用户
-c 修改账号标志位,如 [D] 禁用、[U] 普通用户、[X] 密码永不过期
-u 指定用户名
-w 以 smbpasswd 文件格式输出,便于备份迁移

pdbedit -Lv u1 输出中的关键字段:Unix username、NT username、Account Flags([U ] 表示启用的普通用户,[DU ] 表示被禁用)、User SID、Primary Group SID、Password last set 等。

3.4 服务启动与开机自启

CentOS/RHEL 6(SysV init):

# 启动、停止、重启、重载
/etc/init.d/smb start
/etc/init.d/smb stop
/etc/init.d/smb restart
/etc/init.d/smb reload
/etc/init.d/nmb restart

# 等价的 service 写法
service smb start
service smb restart
service nmb start
service smb status

# 开机自启
chkconfig smb on
chkconfig nmb on
chkconfig --list smb

CentOS/RHEL 7(systemd):

# 启动 Samba 服务
sudo systemctl start smb nmb

# 停止 Samba 服务
sudo systemctl stop smb nmb

# 重启 Samba 服务
sudo systemctl restart smb nmb

# 重新加载配置(不断开现有连接)
sudo systemctl reload smb

# 设置开机自启
sudo systemctl enable smb nmb

# 查看服务状态
sudo systemctl status smb nmb

修改配置后使用 reload 即可让新配置对新连接生效,无需 restart 中断已有会话;但改动 [global] 中的监听相关参数(如 interfaces、smb ports)时需要 restart。

3.5 防火墙与 SELinux 的正确处理

防火墙放行:

# CentOS 7(firewalld)
sudo firewall-cmd --permanent --add-service=samba
sudo firewall-cmd --reload
sudo firewall-cmd --list-all                 # 确认放行结果

# 若只需部分端口,也可逐个放行
sudo firewall-cmd --permanent --add-port=139/tcp
sudo firewall-cmd --permanent --add-port=445/tcp
sudo firewall-cmd --permanent --add-port=137/udp
sudo firewall-cmd --permanent --add-port=138/udp
sudo firewall-cmd --reload

# CentOS 6(iptables)
iptables -I INPUT -p tcp -m multiport --dports 139,445 -j ACCEPT
iptables -I INPUT -p udp -m multiport --dports 137,138 -j ACCEPT
service iptables save
service iptables restart

SELinux 设置:

# 为共享目录打上 samba 上下文(临时,重新打标签会丢失)
sudo chcon -t samba_share_t /soft

# 写入永久规则并生效(推荐)
sudo semanage fcontext -a -t samba_share_t "/soft(/.*)?"
sudo restorecon -Rv /soft

# 查看上下文
ls -Zd /soft

# 常用布尔值
sudo setsebool -P samba_enable_home_dirs on   # 允许共享用户家目录
sudo setsebool -P samba_export_all_ro on      # 允许以只读方式导出任意目录
sudo setsebool -P samba_export_all_rw on      # 允许以读写方式导出任意目录
sudo getsebool -a | grep samba                # 查看所有 samba 相关布尔值

原始笔记中常见 sudo iptables -F + sudo setenforce 0 的写法,属于不推荐的做法:

不推荐写法 问题 推荐替代
sudo iptables -F CentOS 7 默认防火墙是 firewalld,iptables -F 清空的是底层链表,规则会被 firewalld 重新下发,无法可靠放行;且直接清空所有规则等于关闭主机防护 sudo firewall-cmd --add-service=samba --permanent && sudo firewall-cmd --reload;实验环境可临时 sudo systemctl stop firewalld
sudo setenforce 0 全局关闭 SELinux 强制模式,掩盖真实的上下文配置问题,重启后失效,生产环境不可接受 按需精确放开:sudo setsebool -P samba_enable_home_dirs on、sudo chcon -t samba_share_t /soft

setenforce 0 只能作为实验室排错时的临时手段(用于快速判断故障是否由 SELinux 引起),确认后应恢复 setenforce 1 并改用 setsebool / chcon 精确授权。

3.6 实战案例一:匿名可读共享

需求:发布一个所有人无需密码即可浏览和下载的共享 software,对应目录 /soft。

第 1 步:编辑配置文件

CentOS 6(Samba 3.x)可使用 security = share:

[global]
        workgroup = MYGROUP
        server string = li.cluster.com %v
        security = share               # 改为 share,匿名模式
        passdb backend = tdbsam
        load printers = yes
        cups options = raw

[homes]
        comment = Home Directories
        browseable = no
        writable = yes

[test]
        comment = public for everyone
        path = /test
        guest ok = yes                 # 允许匿名登录
        browseable = yes

CentOS 7(Samba 4.x,share 模式已废弃)应改用:

[global]
    workgroup = MYGROUP
    server string = Samba Server Version %v
    log file = /var/log/samba/log.%m
    max log size = 50
    security = user
    map to guest = Bad User            # 关键:用户名不存在时降级为 guest
    guest account = nobody
    passdb backend = tdbsam
    load printers = yes
    cups options = raw

[software]
    comment         = good software
    path            = /soft
    guest ok        = yes
    browseable      = yes
    writeable       = no

第 2 步:创建目录并设置属主权限

sudo mkdir /soft
sudo chown uplooking:uplooking /soft
# 匿名用户以 nobody 身份访问,只读共享保证 o+rx 即可
sudo chmod 755 /soft
echo "hello smb" > /soft/1_hello.txt

CentOS 6 示例目录:

mkdir /test
ls -ld /test
# drwxr-xr-x 5 root root 4096 /test/

第 3 步:SELinux 上下文

sudo chcon -t samba_share_t /soft
# 永久规则
sudo semanage fcontext -a -t samba_share_t "/soft(/.*)?"
sudo restorecon -Rv /soft

第 4 步:防火墙放行

# CentOS 7
sudo firewall-cmd --add-service=samba --permanent
sudo firewall-cmd --reload

# CentOS 6
iptables -I INPUT -p tcp -m multiport --dports 139,445 -j ACCEPT
service iptables save

第 5 步:启动服务

# CentOS 7(仅用 IP 访问时无需 nmb)
sudo systemctl restart smb
sudo systemctl enable smb

# CentOS 6
/etc/init.d/smb reload
chkconfig smb on

第 6 步:客户端验证

smbclient -L //192.168.0.183            # 匿名查看,可见 software 共享
smbclient //192.168.0.183/software      # 匿名登录
# CentOS 6 示例
smbclient -L //10.0.0.2
smbclient //10.0.0.2/test

此时匿名用户只能下载,不能上传/删除。

扩展:让匿名用户可写

在共享段加上 writable = yes。但仅服务允许还不够 —— 匿名用户在 Samba 中以 nobody 身份操作,还必须保证系统目录对 nobody(即 other 位)可写:

ls -ld /test
# drwxr-xr-x 5 root root 4096 /test/

chmod 757 /test        # 让 other 具备 rwx

再次测试即可上传、改名、删除:

smbclient //10.0.0.2/test
smb: \> put install.log
smb: \> rename install.log install
smb: \> rm install.log

扩展:匿名隐藏共享(练习)

创建一个匿名可登录但不在浏览列表中显示的共享资源:

[test]
        comment = public for everyone
        path = /test
        guest ok = yes
        browseable = no

知道共享名的用户可直接 \\IP\test 访问,但在浏览列表中看不到。

share 模式要点总结(CentOS 6):

  • share 模式下,smbpasswd -a 添加的普通用户都无法使用(家目录和共享目录都登录不了);
  • browseable 控制匿名用户客户端是否可见资源;
  • public / guest ok 控制匿名用户是否可以登录资源;
  • writable 控制服务层面是否允许写;
  • 匿名用户以 nobody 身份上传,普通用户以自己的身份上传;
  • 因此除了服务 writable = yes 之外,还需共享目录在系统级别有对应的写权限。

share 与 user 模式四种组合对比(RHEL 6):

模式 共享允许匿名 Linux 客户端 Windows 客户端
share 是 匿名可登录 匿名可登录
share 否 意义不大 意义不大
user 是 匿名和普通都可登录 test,普通也可登录家目录 普通可登录家目录和 test,匿名不能登录 test
user 否 匿名不可登录任何资源;普通可登录 test 和家目录 同 Linux

正常使用场景为第一种(share + 允许匿名)和第四种(user + 拒绝匿名)。

总结:share 模式只允许匿名登录;user 模式只允许普通用户登录。Samba 最常用的是 user 模式(因为要做精细权限控制)。

3.7 实战案例二:指定用户可读写的私有共享

需求:共享 /opt/upload,只有用户 u1 和 u2 可以访问,其中 u1 可读写,u2 只读,拒绝匿名用户。

第 1 步:创建系统用户并加入 Samba 账号库

# 1. 创建系统用户(不允许登录 shell)
sudo useradd -s /sbin/nologin u1
sudo useradd -s /sbin/nologin u2

# 2. 将其加入 Samba 用户库并设置 Samba 密码
sudo smbpasswd -a u1
sudo smbpasswd -a u2

# 3. 确认
sudo pdbedit -L

第 2 步:创建目录与设置属主权限

sudo mkdir -p /opt/upload
sudo chown u1:u1 /opt/upload
sudo chmod 755 /opt/upload

共享目录的属主/属组决定了 Samba 用户实际能否读写,需与 smb.conf 中的 valid users、write list 配合规划。Samba 权限受「服务配置」与「Linux 文件系统权限」双重约束,两者取交集。

第 3 步:配置共享

[upload]
    comment              = Upload
    path                 = /opt/upload
    guest ok             = no                    # 拒绝匿名
    browseable           = yes
    writeable            = yes
    valid users          = u1,u2,+g1             # 允许访问的用户和组
    write list           = u1                    # 读写列表
    read list            = u2,+g1                # 只读列表
    create mode          = 0344                  # 控制新建文件的权限
    force create mode    = 0344
    directory mode       = 0777                  # 控制新建目录的权限
    force directory mode = 0777
    hosts deny           = all                   # 禁止所有客户端
    hosts allow          = 192.168.0.0/24 except 192.168.0.222   # 仅放行本网段,排除 .222

第 4 步:SELinux 与防火墙

sudo semanage fcontext -a -t samba_share_t "/opt/upload(/.*)?"
sudo restorecon -Rv /opt/upload
sudo firewall-cmd --add-service=samba --permanent
sudo firewall-cmd --reload

第 5 步:检查语法并重启

sudo testparm
# CentOS 7
sudo systemctl restart smb nmb
# CentOS 6
/etc/init.d/smb restart

第 6 步:客户端验证

smbclient -L //192.168.0.183 -U u1
smbclient //192.168.0.183/upload -U u1        # 可上传
smbclient //192.168.0.183/upload -U u2        # 只能下载

3.8 实战案例三:多用户组协作共享(SGID + force group)

需求:smb 组的所有成员共同使用 /data/team 目录,组内成员都可读写彼此的文件,但只能删除自己创建的文件;组外用户与匿名用户一律拒绝。

第 1 步:准备组和用户

groupadd smb                     # 创建组
useradd -s /sbin/nologin -G smb u1
useradd -s /sbin/nologin -G smb u2
# 或把已有用户加入组
gpasswd -a u1 smb                # 把用户加入组中
id u1

smbpasswd -a u1
smbpasswd -a u2

第 2 步:创建目录,设置属组、SGID 与粘滞位

sudo mkdir -p /data/team
sudo chgrp smb /data/team
# 2770:组内可读写执行;SGID(2) 使目录内新建文件自动继承属组 smb;other 无任何权限
sudo chmod 2770 /data/team
# 粘滞位:只有文件属主(和 root)能删除自己的文件
sudo chmod o+t /data/team
ls -ld /data/team
# drwxrws--T 2 root smb 4096 /data/team
  • SGID(chmod g+s 或权限位 2xxx):作用于目录时,该目录下新建的文件/子目录自动继承目录的属组,是组协作的基础;
  • 粘滞位(chmod o+t 或权限位 1xxx):目录内的文件只有其属主可以删除或改名,即使其他人对目录有 w 权限,与 /tmp 目录同理。

粘滞位是 Linux 文件系统层面的限制,与 Samba 配置无关,因此必须在服务器本地目录上单独设置。

第 3 步:配置共享,使用 force group 兜底

[team]
    comment          = Team collaboration directory
    path             = /data/team
    guest ok         = no
    browseable       = yes
    writable         = yes
    valid users      = @smb
    write list       = @smb
    force group      = smb              # 强制新建文件的属组为 smb(与 SGID 双重保障)
    create mask      = 0660
    directory mask   = 0770
    inherit permissions = no

如果希望所有成员上传的文件统一归属某个账号(放弃「只能删自己」的能力,换取完全一致的权限),可改用 force user:

    force user = teamadmin
    force group = smb

第 4 步:SELinux、防火墙、启动服务

sudo semanage fcontext -a -t samba_share_t "/data/team(/.*)?"
sudo restorecon -Rv /data/team
sudo setsebool -P samba_export_all_rw on      # 若目录不在标准位置且需读写

sudo firewall-cmd --add-service=samba --permanent
sudo firewall-cmd --reload

sudo testparm
sudo systemctl restart smb nmb        # CentOS 7
# service smb restart; service nmb restart    # CentOS 6

第 5 步:验证

smbclient //192.168.0.183/team -U u1
smb: \> put a.txt
smb: \> ls
# 切换为 u2 登录,应能读写 a.txt,但删除 a.txt 会失败
smbclient //192.168.0.183/team -U u2
smb: \> rm a.txt
# NT_STATUS_CANNOT_DELETE

四、user 模式下的精细权限控制

本章内容基于 RHEL/CentOS 6 + Samba 3.x 实测总结,配置思路同样适用于 CentOS 7。

4.1 普通用户下载与上传的条件

  • 下载条件:登录用户对目标文件有 r 权限;
  • 上传条件:登录用户对共享目录有 w 权限,且服务配置 writable = yes(或 read only = no),并且该用户在 write list 中(若使用了该参数)。

4.2 实现用户之间互相不能删除文件

现象:默认情况下,只要文件拥有者对文件有写权限,其他人(包括自己)就可以删除它。

# a 上传的文件
-rwxr--r--  1 a  a  0  123
-rwxr--r--  1 a  a  0  456
# b 上传的文件
-rwxr--r--  1 b  b  0  678

若将文件权限改为 577(拥有者无写权限),别人删除失败:

chmod 577 /test/456
# -r-xrwxrwx 1 a a 0 456
# b 删除 -> NT_STATUS_CANNOT_DELETE

若将文件权限改为 200(拥有者只有写权限),别人删除成功:

chmod 200 /test/456
# --w------- 1 a a 0 456
# b 删除 -> 成功

结论:只要文件拥有者对该文件有写权限,别人(包括自己)就可以删除;拥有者无写权限,则自己和别人都不能删除。

实现「只能删自己的、不能删别人的」:

chmod o+t /test           # 设置粘滞位

同时要求文件 owner 对自己的文件有写权限。

4.3 create mask 与 directory mask 实践

直接定义上传文件/目录的权限:

[test]
    comment = public for everyone
    path = /test
    browseable = yes
    read only = yes
    writable = yes
    create mask = 0444         # 上传文件权限为 444(默认 744)
    directory mask = 0666      # 上传目录权限为 666(默认 755)
/etc/init.d/smb restart

4.4 精细控制用户读写权限

[test]
    comment = public for everyone
    path = /test
    guest ok = no                # 拒绝匿名
    valid users = a,b            # 只允许 a、b 访问
    write list = a               # 只有 a 可写(上传)
chmod 757 /test
/etc/init.d/smb reload

参数使用要点:

  • valid users = a,b,@group:允许用户 a、b 及 group 组的成员;
  • write list = a,@group:允许写入的用户列表;
  • read list 与 write list 相反,注意它不是控制「哪些人只能读」的额外白名单,而是与 write list 反义的写列表;
  • 组前缀可以使用 @ 或 +;
  • 注意参数是 users(复数),不要误写为 user。

练习 1:a 用户只能上传(不能下载自己上传的文件),b 用户只能下载,拒绝匿名和其它用户。

答案:在上面配置基础上加 create mask = 0344(属主无 r 权限,因此 a 上传后自己读不了;other 有 r,b 可下载)。

练习 2:a 可上传下载,b 只能下载但不能下载 a 上传的文件,拒绝匿名和其它用户。

答案:在上面配置基础上加 create mask = 0704(属主 a 可读写,other 无读权限,b 读不到 a 的文件)。

4.5 包含组的精细控制

需求:a 可上传下载,b 只能下载,smb 组成员可登录并上传下载,拒绝其他普通用户和匿名用户。

[test]
    comment = public for a,b,@smb
    path = /test
    public = no
    valid users = a,b,@smb          # 注意 users 不要写成 user
    write list = a,@smb             # @ 也可以使用 +

创建用户和组:

groupadd smb
useradd smb1 -g smb
useradd smb2 -g smb
smbpasswd -a smb1
smbpasswd -a smb2
id smb1
# uid=521(smb1) gid=521(smb) groups=521(smb)

4.6 综合案例:boss / secretary / it 组

需求:

  • boss:可上传下载(可下载所有人的文件)、删除自己上传的文件;
  • secretary:只能下载(可下载所有人的文件);
  • it 组成员(it1、it2):可登录、上传、下载和删除自己的文件;组成员之间不能互删、不能互相下载别人的文件,但可以下载 boss 上传的文件;
  • 拒绝其他普通用户和匿名用户。
useradd boss
useradd secretary
groupadd it
useradd -g it it1
useradd -g it it2

smbpasswd -a boss
smbpasswd -a secretary
smbpasswd -a it1
smbpasswd -a it2
[test]
    comment = hahahahahaha
    path = /test
    public = no
    browseable = no
    valid users = boss,secretary,@it
    write list = boss,@it
    create mask = 0704
mkdir /test
chmod 757 /test
chmod o+t /test

扩展讨论:

  • 若再加一个 sale 组,需求与 it 相同:由于权限只能用 owner/group/other 三档区分,sale 和 it 组成员会互相能下载。最好的做法是每个组使用不同的目录(分别建共享)。若硬要放在同一目录,可把两个组的 GID 改成同一个公共组,但这相当于把两组合并对待,失去隔离意义。
  • 若需求变为「boss 能删除所有人的文件」:理论上无法仅靠 Samba 配置实现(粘滞位会阻止);一种方法是 chown boss.boss /test 让 boss 成为目录 owner(目录属主可删除粘滞位目录内的任意文件);另一种方法是在共享段使用 admin users = boss,让 boss 以 root 身份操作。

4.7 综合案例:a / b / c 差异化权限

需求:

  • a:上传下载(可下载所有人的文件);
  • b:只能下载(可下载所有人的文件);
  • c:可上传,但只能下载自己上传的文件;
  • 都可删除自己的文件,互相不能删;拒绝其他用户和匿名用户。

关键是让 a、c 上传的文件权限分别为 rwx---r-- 形式,并把 c 加入 a 组:

useradd a
useradd b
useradd c
usermod -G a c

smbpasswd -a a
smbpasswd -a b
smbpasswd -a c

mkdir /test
chmod 757 /test
chmod o+t /test
[test]
    comment = test resource
    path = /test
    guest ok = no
    browseable = yes
    valid users = a,b,c
    write list = a,c
    create mask = 0704
/etc/init.d/smb restart

另一种思路(可选):让 a 上传文件为 rwxr-----、c 上传文件为 rwxr-----,并把 b 加入 a、c 组,通过组权限位让 b 能读到二者的文件。

4.8 不同用户不同 create mask(用户子配置文件 config file = %U)

当不同用户对同一共享需要不同权限策略(例如 u1 可上传下载、u2 只能下载且看不到 u1 上传的文件)时,可在 [global] 中使用 config file 为每个用户指定独立的配置文件:

# [global] 中添加
config file = /etc/samba/smb.conf.%U     # %U 表示登录用户名

%U 是 Samba 的变量替换符,表示 当前登录的用户名。用户 u1 登录时,Samba 会尝试加载 /etc/samba/smb.conf.u1;若该文件存在则以它替代主配置生效,不存在则继续使用 /etc/samba/smb.conf。由此可为单个用户定制共享策略。

需求示例:a 上传为默认 0744,c 上传为 0344(属主无读权限)。

主配置 /etc/samba/smb.conf:

[test]
    comment = 35's test resource
    path = /test
    public = no
    browseable = yes
    valid users = a,b,c
    write list = a
    create mask = 0744

为 c 用户单独创建子配置文件:

vim /etc/samba/smb.conf.c
[test]
    comment = 35's test resource
    path = /test
    writable = yes
    create mask = 0344         # 没有读权限
/etc/init.d/smb restart

config file 的另一种替代思路是把同一物理目录做成两个不同共享名,在不同共享段里分别控制权限。


五、客户端访问

5.1 Linux 客户端:smbclient

smbclient 由 samba-client 包提供,无需挂载即可直接测试和访问共享,是排查共享是否生效的首选工具。

列举服务器上的共享:

smbclient -L //192.168.0.183
smbclient -L //10.0.0.2
# Password:             # 直接回车即以匿名身份查看

-L 表示列出目标主机对外提供的共享名、类型与注释。默认会提示输入密码,直接回车即以匿名身份查看;也可用 -U 指定用户:

smbclient -L //10.0.0.2 -U a
smbclient -L //192.168.0.183 -U u1
# 新版本可用 -N 表示不提示密码(匿名)
smbclient -L //192.168.0.183 -N

注意 browseable = No 的共享不会出现在列表中,但仍可直接连接。若登录失败报 NT_STATUS_LOGON_FAILURE,检查该系统用户是否已通过 smbpasswd -a 加入 Samba 账号库。

交互式登录共享:

smbclient //192.168.0.183/software
smbclient //192.168.0.183/share -U u1
smbclient //10.0.0.2/a -U a

连接成功后进入 smb: \> 提示符,可使用类似 FTP 的交互命令:

命令 作用
ls 列出共享内的文件
pwd 显示当前所在目录
cd 切换目录
mkdir 创建目录
get 1_hello.txt 下载文件
mget 批量下载
put file.txt 上传文件(需共享可写)
mput 批量上传
rm 删除文件
rename 重命名文件
lcd 切换本地目录
!命令 执行本地 shell 命令
help / ? 查看命令帮助
exit 或 quit 退出

操作示例:

smbclient //10.0.0.2/a -U a
# smb: \> pwd
# Current directory is \\10.0.0.2\a\
# smb: \> ls
# smb: \> put install.log
# smb: \> get vvv
# smb: \> rm vvv
# smb: \> rename install.log install

其他常用选项:

smbclient //server/share -U user%password     # 在命令行直接给出密码(会暴露在历史记录中)
smbclient //server/share -A /root/.smbcred    # 从凭据文件读取账号密码
smbclient //server/share -c "ls; get a.txt"   # 非交互执行命令,便于脚本化
smbclient //server/share -m SMB3              # 指定协议版本

5.2 Linux 客户端:mount 挂载 cifs

挂载依赖 cifs-utils 包提供的 mount.cifs,需先安装:

sudo yum install cifs-utils -y

基本挂载:

# 用匿名用户挂载
sudo mount //192.168.0.183/software /mnt -o guest

# 指定用户名挂载(会提示输入密码)
sudo mount //192.168.0.183/software /mnt -o username=u1

# 显式指定文件系统类型
mount -t cifs -o username=a //10.0.0.2/a /mnt
# Password:

# 同时给出用户名和密码(不安全,密码会进入命令历史与 ps 输出)
sudo mount -t cifs //192.168.0.183/share /mnt -o username=u1,password=123456

挂载后即可使用 cp、ls、mv、rm 等普通命令操作,df -h 可看到挂载点。卸载使用 umount /mnt。

常用挂载选项:

选项 说明
username= 登录 Samba 的用户名
password= 密码(不推荐明文写在命令或 fstab 中)
guest 匿名挂载,等价于空用户名空密码
credentials= 指定凭据文件路径,避免密码明文
uid= / gid= 挂载后本地看到的文件属主/属组,常设为使用该目录的本地用户,否则默认全部归 root
file_mode= / dir_mode= 挂载后本地呈现的文件/目录权限,如 file_mode=0644,dir_mode=0755
vers= SMB 协议版本,如 vers=1.0、vers=2.0、vers=2.1、vers=3.0。服务端禁用 SMB1 时必须指定 2.0 及以上
iocharset=utf8 指定字符集,解决中文文件名乱码
sec= 认证方式,如 ntlmssp(默认)、ntlm、krb5
ro / rw 只读 / 读写挂载
_netdev 声明该挂载依赖网络,供 systemd 在网络就绪后再挂载
noauto 开机不自动挂载,需手工 mount

完整示例:

sudo mount -t cifs //192.168.0.183/share /mnt/samba \
  -o credentials=/root/.smbcred,uid=1000,gid=1000,file_mode=0644,dir_mode=0755,vers=3.0,iocharset=utf8

credentials 凭据文件(避免明文密码):

sudo vim /root/.smbcred
username=u1
password=your_pass
domain=MYGROUP
# 必须收紧权限,否则密码等于公开
sudo chmod 600 /root/.smbcred
sudo chown root:root /root/.smbcred

开机自动挂载(/etc/fstab):

//192.168.0.183/software  /mnt/samba  cifs  username=u1,password=your_pass,_netdev  0  0

推荐使用凭据文件的写法:

//192.168.0.183/share  /mnt/samba  cifs  credentials=/root/.smbcred,uid=1000,gid=1000,vers=3.0,iocharset=utf8,_netdev  0  0

写入后可先测试:

sudo mount -a
df -h | grep samba

生产环境建议将凭据写入独立文件(如 /root/.smbcred),并通过 credentials=/root/.smbcred 引用,避免密码明文暴露在 /etc/fstab 中(/etc/fstab 默认对所有用户可读)。若网络未就绪导致开机挂载失败,务必加 _netdev,或改用 noauto + 手工/自动挂载单元。

5.3 Windows 客户端访问

方式一:直接访问 UNC 路径

  1. 打开「运行」(Win + R),输入 \\192.168.1.x(Samba 服务器 IP)或 \\192.168.1.x\共享名;
  2. 在弹出的认证窗口中输入 Samba 用户名和密码;
  3. 匿名共享则无需输入凭据即可进入。

方式二:映射网络驱动器(开机自动连接)

  • 右键「我的电脑 / 此电脑」→ 工具 → 映射网络驱动器;
  • 「文件夹」处填写 \\10.0.0.2\a;
  • 勾选「登录时重新连接」,在「其他用户名 / 使用其他凭据」中填写用户名和密码。

命令行方式:

net use Z: \\192.168.0.183\share /user:u1 your_pass /persistent:yes
net use                              :: 查看当前连接
net use Z: /del                      :: 断开指定驱动器
net use * /del                       :: 清除所有连接缓存(排错常用)

Windows 凭据管理器:控制面板 → 用户账户 → 凭据管理器 → Windows 凭据,可查看/添加/删除已保存的 Samba 服务器凭据。当密码修改后连接仍失败,通常是旧凭据被缓存,需在此删除对应条目,或执行 net use * /del 后重试。

Windows 端常见无法访问的原因:

  1. Windows 防火墙拦截,或第三方安全软件阻止了「文件和打印机共享」;测试环境可先关闭 Windows 防火墙;
  2. 客户端缓存了旧的错误凭据(用 net use * /del 或凭据管理器清除);
  3. Windows 10/11 默认关闭了 SMB1 和「不安全的来宾登录」,访问匿名共享会报「你不能访问此共享文件夹,因为你的组织的安全策略阻止未经身份验证的来宾访问」。解决办法:让服务端启用 SMB2/SMB3 并使用带账号的访问;或在客户端组策略「计算机配置 → 管理模板 → 网络 → Lanman 工作站 → 启用不安全的来宾登录」中开启(不推荐);
  4. 工作组名称不一致导致网上邻居中看不到(但用 IP 直连仍可用);
  5. 服务器端未启动 nmb,导致无法通过计算机名访问,改用 IP 即可;
  6. 445 端口被运营商或本地策略封禁。

六、状态查看与运维

6.1 smbstatus 查看连接与锁

sudo smbstatus            # 查看所有活动会话、已连接共享和文件锁
sudo smbstatus -b         # 仅显示简要的会话列表(brief)
sudo smbstatus -S         # 仅显示共享连接情况(shares)
sudo smbstatus -L         # 仅显示文件锁(locks)
sudo smbstatus -p         # 仅显示 smbd 进程列表
sudo smbstatus -u u1      # 只看指定用户的连接

输出包含三部分:

  • Samba version / PID / Username / Group / Machine:哪个用户从哪台机器连接;
  • Service (pid) machine Connected at:连接了哪些共享,连接时间;
  • Locked files:当前被打开/锁定的文件,可定位「文件被占用无法删除」的来源。

强制断开某个连接可直接结束对应的 smbd 进程(谨慎操作):

sudo kill <PID>

6.2 日志位置与级别调整

日志目录为 /var/log/samba/:

文件 内容
log.smbd smbd 主进程日志
log.nmbd nmbd 主进程日志
log.<客户端名或IP> 由 log file = /var/log/samba/log.%m 生成的每客户端日志,排错主要看这里

调整日志级别(0~10,默认 0 或 1,数字越大越详细):

[global]
    log file = /var/log/samba/log.%m
    max log size = 50            # KB,0 表示不限制
    log level = 3                # 排错时临时提高,排完改回 1
    # 也可分模块设置
    # log level = 1 auth:3 winbind:2
sudo systemctl reload smb
tail -f /var/log/samba/log.192.168.0.100

其他排错工具:

testparm -s                       # 校验配置
smbclient -L //localhost -N       # 本机自测共享是否发布
ss -tulnp | grep -E 'smbd|nmbd'   # 检查监听端口(CentOS 7)
netstat -ntlup | grep bd          # CentOS 6
ausearch -m avc -ts recent        # 查看近期 SELinux 拒绝记录
grep smbd /var/log/audit/audit.log | audit2why

6.3 打印共享简述

Samba 可以把 Linux(CUPS)上的打印机共享给 Windows 客户端。

[global]
    load printers = yes           # 自动加载 /etc/printcap 中的全部打印机
    printing = cups               # 打印系统类型:cups / lprng / bsd
    printcap name = cups
    cups options = raw            # raw 表示打印数据由客户端驱动生成,服务端不再处理

[printers]
    comment = All Printers
    path = /var/spool/samba       # 打印假脱机目录
    browseable = no
    guest ok = no
    writable = no
    printable = yes               # 打印共享必须为 yes

# 单独共享某台打印机
[hp-laser]
    comment = HP LaserJet
    path = /var/spool/samba
    printer name = hp-laser
    printable = yes
    guest ok = yes
    valid users = @printusers

要点:

  • printable = yes 是打印共享的标志,普通文件共享绝不能设置;
  • 假脱机目录 /var/spool/samba 需要 1777 权限(含粘滞位);
  • cups options = raw 时,Windows 端需安装与打印机匹配的驱动;
  • 可另外配置 [print$] 共享用于向 Windows 客户端自动分发打印驱动。

6.4 Samba 加入 AD/NT 域简述

在有 Windows 域控的环境中,可让 Samba 使用域账号认证,避免在 Linux 端重复建账号。核心是 security = ads(AD 域)或 security = domain(NT 域),并启用 winbindd。

[global]
    workgroup = EXAMPLE                 # 域的 NetBIOS 名
    realm = EXAMPLE.COM                 # AD 域的 Kerberos realm(大写)
    security = ads
    idmap config * : backend = tdb
    idmap config * : range = 10000-19999
    idmap config EXAMPLE : backend = rid
    idmap config EXAMPLE : range = 100000-999999
    winbind use default domain = yes
    winbind offline logon = yes
    template shell = /bin/bash
    template homedir = /home/%D/%U

大致步骤:

# 1. 安装依赖
yum install samba samba-winbind samba-winbind-clients krb5-workstation -y

# 2. 确保 DNS 指向域控、时间与域控同步(Kerberos 对时间敏感)
ntpdate <域控IP>            # 或使用 chronyd

# 3. 加入域
net ads join -U Administrator
# NT 域则使用:net rpc join -U Administrator

# 4. 启动 winbind
systemctl enable --now winbind        # CentOS 7
service winbind start                 # CentOS 6

# 5. 验证
net ads testjoin
wbinfo -u                # 列出域用户
wbinfo -g                # 列出域组
wbinfo -a EXAMPLE\\user  # 测试域用户认证
getent passwd EXAMPLE\\user   # 需在 /etc/nsswitch.conf 中加入 winbind

在 /etc/nsswitch.conf 中加入 winbind,使系统能解析域账号:

passwd:     files winbind
group:      files winbind

此后共享段中可直接使用域账号与域组:

[share]
    path = /data/share
    valid users = @"EXAMPLE\Domain Users"
    write list = @"EXAMPLE\IT"

若无域环境,保持 security = user + 本地账号即可,本节可跳过。

6.5 注意事项汇总

  1. 权限一致性:Samba 权限受自身配置和 Linux 文件系统权限双重约束,需确保共享目录对系统用户有足够的读写权限。
  2. SELinux:若开启 SELinux,共享目录需设置正确的上下文(samba_share_t),必要时执行 setsebool -P samba_enable_home_dirs on。
  3. 防火墙:确保已开放 SMB 相关端口(TCP 139、445,UDP 137、138)。
  4. security 模式:share 模式已在新版 Samba(4.x / CentOS 7)中废弃,推荐使用 user 模式 + map to guest = Bad User。
  5. 用户隔离:Samba 用户密码与系统用户密码独立管理,修改 Samba 密码不会影响系统密码。
  6. 配置备份:修改 smb.conf 前建议先备份,并使用 testparm 验证语法。
  7. 协议版本:禁用 SMB1(min protocol = SMB2)可显著提升安全性,但需评估老旧客户端与设备的兼容性。

七、排错清单

按「网络 → 防火墙 → SELinux → 服务配置 → 系统权限」的顺序逐层排查。

7.1 无法浏览到共享列表

可能原因 检查与解决
服务未启动 systemctl status smb nmb / service smb status;用 ss -tulnp 过滤 smbd 确认监听
配置语法错误导致未加载 testparm -s,确认输出 Loaded services file OK.
防火墙拦截 firewall-cmd --list-all 确认放行 samba;CentOS 6 检查 iptables -L -n
browseable = no 该共享被故意隐藏,直接用 smbclient //IP/共享名 或 \\IP\共享名 连接
hosts allow / hosts deny 拦截 检查全局段与共享段的访问控制列表,注意 hosts deny = all 的存在
available = no 共享被禁用,改为 yes 或删除该行
用不了主机名 未启动 nmb 或 NetBIOS 名称解析失败,改用 IP 访问,或配置 WINS / lmhosts
客户端和服务器不在同一广播域 网上邻居自动发现依赖广播,跨网段需 WINS 或直接用 IP

7.2 能看到共享但打不开(认证失败)

现象 / 原因 解决
NT_STATUS_LOGON_FAILURE 该系统用户未加入 Samba 账号库,执行 smbpasswd -a 用户名;或密码输错;用 pdbedit -L 确认账号存在
账号被禁用 pdbedit -Lv 用户名 查看 Account Flags 是否为 [DU...],用 smbpasswd -e 启用
NT_STATUS_ACCESS_DENIED 用户不在 valid users 中,或被 invalid users 拒绝
匿名访问被拒 CentOS 7 需 security = user + map to guest = Bad User + 共享段 guest ok = yes
Windows 缓存了旧凭据 net use * /del,或在凭据管理器中删除该服务器条目
NT_STATUS_BAD_NETWORK_NAME 共享名拼写错误,或 path 指向的目录不存在
系统用户 shell 为 nologin 导致 PAM 拒绝 Samba 认证一般不受 shell 限制;若配置了 obey pam restrictions = yes,检查 PAM 与账号是否被锁定(passwd -S 用户名)

7.3 可读不可写

依次检查三个层面:

  1. 服务层:共享段是否 writable = yes(或 read only = no);同义/反义参数是否被后面的行覆盖;该用户是否在 write list 中,是否被 read list 命中;
  2. 文件系统层:ls -ld /共享目录 确认登录用户对目录有 w 和 x 权限。匿名共享要给 other 位写权限(如 chmod 757 /test),私有共享把目录属主/属组改成对应用户或组;
  3. SELinux 层:ls -Zd /共享目录 确认是 samba_share_t,只读上下文或错误上下文会导致只能读不能写;必要时 setsebool -P samba_export_all_rw on。

另外注意粘滞位与 create mask:create mask 过严(如 0444)会导致上传后的文件自己都改不动;粘滞位会阻止删除别人的文件(这通常是预期行为)。

7.4 中文文件名乱码

服务端配置:

[global]
    unix charset = UTF-8
    dos charset = cp936
    display charset = UTF-8

Linux 客户端挂载时指定字符集:

mount -t cifs //IP/share /mnt -o username=u1,iocharset=utf8

同时确认服务器 shell 的 LANG 环境变量(echo $LANG 应为 zh_CN.UTF-8 或 en_US.UTF-8),以及 Windows 端系统区域设置。

7.5 SELinux 拒绝访问

# 快速判断是否 SELinux 引起(临时)
getenforce
setenforce 0        # 若此时正常,则问题在 SELinux;确认后立即 setenforce 1

# 查看被拒绝的记录并获得建议
ausearch -m avc -ts recent
grep smbd /var/log/audit/audit.log | audit2why
grep smbd /var/log/audit/audit.log | audit2allow -M mysamba   # 生成自定义策略(谨慎)

# 正确做法
semanage fcontext -a -t samba_share_t "/共享目录(/.*)?"
restorecon -Rv /共享目录
setsebool -P samba_enable_home_dirs on
setsebool -P samba_export_all_rw on

7.6 SMB1 被禁导致老客户端连不上

现象:Windows XP、老式打印机/扫描仪、部分嵌入式 NAS 无法连接,日志出现协议协商失败。

  • 首选方案:升级客户端或设备固件,使其支持 SMB2/SMB3;
  • 隔离方案:单独部署一台仅供老设备使用的 Samba 实例,放在独立网段并严格限制 hosts allow;
  • 临时兼容(有安全风险,仅限内网隔离环境):
[global]
    min protocol = NT1
    max protocol = SMB3
    # 老客户端可能还需要
    ntlm auth = yes
    server min protocol = NT1

反之,若是新版 Linux 客户端连接老服务器失败,则在挂载时降低版本:

mount -t cifs //IP/share /mnt -o username=u1,vers=1.0

7.7 445 端口被占用或被拦截

# 检查端口占用(若被其他程序占用,smbd 会启动失败)
ss -tulnp | grep -E ':445|:139'
netstat -ntlup | grep -E '445|139'
lsof -i :445

# 检查是否被防火墙拦截
firewall-cmd --list-all
iptables -L -n --line-numbers

# 从客户端测试连通性
telnet 192.168.0.183 445
nc -zv 192.168.0.183 445
nmap -p 139,445 192.168.0.183

其他可能:

  • 运营商在公网侧封禁 139/445,因此 Samba 不适合直接跨公网使用,应通过 VPN 或 SSH 隧道;
  • 云主机安全组未放行入站 139/445;
  • 若确需更换端口,可在 [global] 中设置 smb ports = 445 139(注意多数 Windows 客户端不支持自定义端口)。

7.8 排错速查命令清单

testparm -s                          # 配置语法
systemctl status smb nmb             # 服务状态(CentOS 7)
service smb status                   # 服务状态(CentOS 6)
ss -tulnp | grep -E 'smbd|nmbd'      # 监听端口
smbstatus                            # 当前连接与文件锁
pdbedit -L                           # Samba 账号列表
pdbedit -Lv u1                       # 账号详情与标志位
ls -ld /共享目录                      # 系统权限
ls -Zd /共享目录                      # SELinux 上下文
getsebool -a | grep samba            # SELinux 布尔值
firewall-cmd --list-all              # 防火墙放行情况
tail -f /var/log/samba/log.客户端IP   # 实时日志
smbclient -L //localhost -N          # 本机自测

八、练习

练习一:配置一个基本的 Samba 共享

  1. 处理防火墙和 SELinux(推荐精确放行,实验室可临时关闭):

     # 不推荐但常见于旧笔记的做法
     sudo iptables -F
     sudo setenforce 0
    
     # 推荐做法
     sudo firewall-cmd --add-service=samba --permanent
     sudo firewall-cmd --reload
     sudo chcon -t samba_share_t /soft
  2. 编辑配置文件增加一个共享:

     sudo vim /etc/samba/smb.conf
     [software]
         comment         = good software
         path            = /soft
         guest ok        = yes
         browseable      = yes
         writeable       = no
  3. 创建共享目录:

     sudo mkdir /soft
     sudo chown uplooking:uplooking /soft
     echo "hello smb" > /soft/1_hello.txt
  4. 启动/重启服务:

     sudo systemctl restart smb        # CentOS 7
     # /etc/init.d/smb restart         # CentOS 6
  5. 列出共享并登录共享:

     smbclient -L //192.168.0.*
     smbclient //192.168.0.*/software

练习二:创建一个 Samba 用户并观察状态变化

按以下步骤操作,并观察每步中用户详细信息的差异:

  1. 创建一个系统用户 u1;
  2. 修改用户 u1 在 Samba 服务里的密码;
  3. 把用户 u1 添加为 Samba 服务的用户;
  4. 列出 Samba 用户 u1 的详细信息;
  5. 把用户 u1 踢出 Samba 用户库;
  6. 列出 Samba 用户 u1 的详细信息;
  7. 把用户 u1 重新添加为 Samba 服务的用户;
  8. 列出 Samba 用户 u1 的详细信息;
  9. 禁用 Samba 用户 u1;
  10. 列出 Samba 用户 u1 的详细信息;
  11. 启用 Samba 用户 u1;
  12. 列出 Samba 用户 u1 的详细信息;
  13. 对比第 4、6、8、10、12 步详细信息的不同(重点看 Account Flags)。

参考命令:

useradd u1
smbpasswd -a u1
pdbedit -Lv u1
smbpasswd -x u1
pdbedit -Lv u1
smbpasswd -a u1
pdbedit -Lv u1
smbpasswd -d u1
pdbedit -Lv u1
smbpasswd -e u1
pdbedit -Lv u1

预期结果:删除后 pdbedit -Lv u1 查不到该用户;禁用后 Account Flags 中出现 D;启用后 D 消失。

练习三:禁止用户登录自己的家目录

把配置文件中 [homes] 共享的相关行注释掉:

#[homes]
#       comment = Home Directories
#       browseable = no
#       writable = yes

然后使用普通用户验证其家目录共享不再出现:

smbclient -L //10.1.2.3 -U u1

练习四:配置精细化权限共享

按以下要求创建一个共享:

  1. 用户 u1 和属于 smb 组的用户可以上传下载(valid users = u1,u2,+smb,write list = u1,+smb);
  2. 用户 u2 只能下载不能上传(通过 read list 或不列入 write list);
  3. 用户 u2 能下载所有人上传的文件;
  4. 用户 u2 不能下载 u1 上传的文件(给 u1 单独配置文件,在其中修改上传文件的权限);
  5. 用户之间不能删除别人上传的文件(目录加粘滞位 chmod o+t);
  6. 该共享不显示在共享列表中(browseable = no);
  7. 只允许来自 192.168.0.0/24 的客户端,但排除 192.168.0.222(hosts allow);
  8. 拒绝匿名用户和其他用户访问(guest ok = no)。

准备组和用户:

groupadd smb            # 创建组
gpasswd -a u1 smb       # 把用户加入组中
mkdir -p /tmp/share
chmod 1777 /tmp/share   # 或 chmod o+t /tmp/share

参考配置 —— 主配置文件 /etc/samba/smb.conf:

[global]
    config file = /etc/samba/smb.conf.%U
    # ... global 部分的其它设置省略

[share]
    comment         = Share data
    path            = /tmp/share
    valid users     = u1,u2,+smb
    write list      = u1,+smb
    read list       = u2
    browseable      = No
    guest ok        = no
    hosts allow     = 192.168.0.0/255.255.255.0 except 192.168.0.222

u1 用户专用配置文件 /etc/samba/smb.conf.u1:

[share]
    comment             = Share data
    path                = /tmp/share
    valid users         = u1
    write list          = u1
    browseable          = No
    hosts allow         = 192.168.0.0/255.255.255.0 except 192.168.0.222
    create mode         = 0400
    force create mode   = 0400

设置共享目录的粘滞位(sticky bit),使用户只能删除自己创建的文件:

sudo chmod o+t /tmp/share

通过将 u1 上传文件权限设为 0400,使 u2 等其他用户无法读取 u1 上传的文件,从而实现「u2 不能下载 u1 上传的文件」。

练习五:搭建匿名只读共享并用 smbclient 验证

完整操作顺序如下:

# 1. 放行防火墙(CentOS 7 默认使用 firewalld)
sudo firewall-cmd --add-service=samba --permanent
sudo firewall-cmd --reload

# 2. 编辑共享配置
sudo vim /etc/samba/smb.conf

# 3. 准备共享目录
sudo mkdir /soft
sudo chown uplooking:uplooking /soft

# 4. 处理 SELinux:为共享目录打上 samba 上下文
sudo chcon -t samba_share_t /soft
# 如需共享用户家目录,另需开启布尔值
sudo setsebool -P samba_enable_home_dirs on

# 5. 重启服务(仅用 IP 访问时无需 nmb)
sudo systemctl restart smb

# 6. 客户端验证共享是否发布成功
smbclient -L //192.168.0.183

练习六:CentOS 6 user 模式权限控制系列练习

  1. 创建一个匿名可登录但不在浏览列表中显示的隐藏共享(参见 3.6 扩展)。
  2. user 模式下实现 a 可上传下载、b 只能下载、拒绝匿名及其他用户(参见 4.4)。
  3. user 模式下实现 a 只能上传不能下载自己上传的文件、b 只能下载(参见 4.4 练习 1,答案:create mask = 0344)。
  4. user 模式下实现 a 可上传下载、b 只能下载且不能下载 a 上传的文件(参见 4.4 练习 2,答案:create mask = 0704)。
  5. user 模式下实现 boss / secretary / it 组的差异化权限(参见 4.6)。
  6. user 模式下实现 a / b / c 差异化权限,并用 config file = %U 为不同用户设置不同 create mask(参见 4.7、4.8)。
  7. 在第 5 题基础上增加 sale 组(需求与 it 相同),讨论能否仅靠 Samba 参数实现;若要求 boss 能删除所有人的文件,讨论可行的实现方式(参见 4.6 扩展讨论)。
最后修改:2026 年 09 月 20 日
如果觉得我的文章对你有用,请随意赞赏