diff --git a/bundles/samba/files/override.conf b/bundles/samba/files/override.conf new file mode 100644 index 0000000..35693b4 --- /dev/null +++ b/bundles/samba/files/override.conf @@ -0,0 +1,3 @@ +[Service] +RestartSec=10 +Restart=on-failure diff --git a/bundles/samba/files/smb.conf b/bundles/samba/files/smb.conf new file mode 100644 index 0000000..325b040 --- /dev/null +++ b/bundles/samba/files/smb.conf @@ -0,0 +1,39 @@ +[global] +workgroup = KUNBOX +server string = ${node.name} samba +dns proxy = no +max log size = 1000 +syslog = 1 +syslog only = 1 +panic action = /usr/share/samba/panic-action %d +encrypt passwords = true +passdb backend = tdbsam +obey pam restrictions = yes +map to guest = bad user +load printers = no +usershare allow guests = yes +allow insecure wide links = yes +% for name, opts in sorted(node.metadata.get('samba/shares', {}).items()): + +[${name}] +browseable = yes +comment = ${opts.get('comment', f'share of {opts["path"]}')} +fake oplocks = yes +force group = ${opts.get('force_group', 'nobody')} +force user = ${opts.get('force_user', 'nogroup')} +% if opts.get('guest_ok', True): +guest ok = yes +% else: +guest ok = no +% endif +locking = no +path = ${opts['path']} +printable = no +read only = no +vfs objects = catia fruit +writable = ${'yes' if opts.get('writable', False) else 'no'} +% if opts.get('follow_symlinks', True): +follow symlinks = yes +wide links = yes +% endif +% endfor diff --git a/bundles/samba/items.py b/bundles/samba/items.py new file mode 100644 index 0000000..333a338 --- /dev/null +++ b/bundles/samba/items.py @@ -0,0 +1,59 @@ +svc_systemd = { + 'nmbd': { + 'needs': { + 'pkg_apt:samba', + }, + }, + 'smbd': { + 'needs': { + 'pkg_apt:samba', + }, + }, +} + +files = { + '/etc/samba/smb.conf': { + 'content_type': 'mako', + 'triggers': { + 'svc_systemd:nmbd:restart', + 'svc_systemd:smbd:restart', + }, + }, + '/etc/systemd/system/nmbd.service.d/bundlewrap.conf': { + 'source': 'override.conf', + 'triggers': { + 'action:systemd-reload', + 'svc_systemd:nmbd:restart', + }, + }, + '/etc/systemd/system/smbd.service.d/bundlewrap.conf': { + 'source': 'override.conf', + 'triggers': { + 'action:systemd-reload', + 'svc_systemd:smbd:restart', + }, + }, +} + +last_action = set() +for user, uconfig in node.metadata.get('users', {}).items(): + if ( + 'password' not in uconfig + or uconfig.get('delete') + or user in ('root',) + ): + continue + + actions[f'smbpasswd_for_user_{user}'] = { + 'command': f'smbpasswd -a -s {user}', + 'unless': f'pdbedit -L | grep -E "^{user}:"', + 'data_stdin': uconfig['password'] + '\n' + uconfig['password'], + 'needs': { + 'pkg_apt:samba', + f'user:{user}', + }, + 'after': last_action, + } + last_action = { + f'action:smbpasswd_for_user_{user}', + } diff --git a/bundles/samba/metadata.py b/bundles/samba/metadata.py new file mode 100644 index 0000000..7b9400c --- /dev/null +++ b/bundles/samba/metadata.py @@ -0,0 +1,26 @@ +from bundlewrap.metadata import atomic + +defaults = { + 'apt': { + 'packages': { + 'samba': {}, + 'samba-vfs-modules': {}, + } + } +} + + +@metadata_reactor.provides( + 'firewall/port_rules', +) +def firewall(metadata): + return { + 'firewall': { + 'port_rules': { + '137/udp': atomic(metadata.get('samba/restrict-to', set())), + '138/udp': atomic(metadata.get('samba/restrict-to', set())), + '139/tcp': atomic(metadata.get('samba/restrict-to', set())), + '445/tcp': atomic(metadata.get('samba/restrict-to', set())), + }, + }, + } diff --git a/nodes/home/nas.py b/nodes/home/nas.py index 9c2c62f..0ca0790 100644 --- a/nodes/home/nas.py +++ b/nodes/home/nas.py @@ -11,6 +11,7 @@ nodes['home.nas'] = { 'mosquitto', 'nfs-server', 'rsyslogd', + 'samba', 'scansnap', 'smartd', 'vmhost', @@ -167,6 +168,17 @@ nodes['home.nas'] = { 'home', }, }, + 'samba': { + 'shares': { + 'music': { + 'path': '/storage/nas/Musik', + 'force_group': 'nas', + }, + }, + 'restrict-to': { + '172.19.138.0/24', + }, + }, 'smartd': { 'disks': { '/dev/nvme0',