{ lib, config, namespace, ... }: with lib; let cfg = config.${namespace}.samba; makeShare = name: share: let isTimeMachine = share.enableTimeMachine; baseAttrs = { path = share.sharePath; browseable = if share.browseable then "yes" else "no"; "read only" = if share.readOnly then "yes" else "no"; "guest ok" = if share.guestOk then "yes" else "no"; "create mask" = share.createMask; "directory mask" = share.directoryMask; } // optionalAttrs (cfg.forceGroup != "") { "force group" = cfg.forceGroup; } // optionalAttrs (cfg.forceUser != "") { "force user" = cfg.forceUser; }; timeMachineAttrs = { "vfs objects" = "catia fruit streams_xattr"; "fruit:aapl" = "yes"; "fruit:time machine" = "yes"; } // optionalAttrs (share.timeMachineMaxSize != "") { "fruit:time machine max size" = share.timeMachineMaxSize; }; in nameValuePair name (baseAttrs // optionalAttrs isTimeMachine timeMachineAttrs); sambaShares = mapAttrs' makeShare cfg.shares; in { imports = [ ./options.nix ]; config = mkIf cfg.enable { # Make shares visible for Windows clients via WS-Discovery services.samba-wsdd = { enable = true; openFirewall = true; }; services.samba = { enable = true; openFirewall = true; nsswins = true; nmbd.enable = true; settings = { global = { workgroup = "WORKGROUP"; "server string" = config.networking.hostName; "netbios name" = config.networking.hostName; security = "user"; "hosts allow" = cfg.hostsAllow; "hosts deny" = "0.0.0.0/0"; "guest account" = "nobody"; "map to guest" = "bad user"; } // optionalAttrs cfg.enableTimeMachine { # Required globals for macOS Time Machine over SMB3 "fruit:aapl" = "yes"; "fruit:model" = "MacSamba"; }; } // sambaShares; }; }; }