Skip to content

Instantly share code, notes, and snippets.

@pshirshov
Last active October 10, 2024 12:24
Show Gist options
  • Save pshirshov/135d508dc762f168fb73f20c104232d9 to your computer and use it in GitHub Desktop.
Save pshirshov/135d508dc762f168fb73f20c104232d9 to your computer and use it in GitHub Desktop.
FreeRadius, OpenLDAP and Samba on NixOS howto
  1. Install NixOS
  2. Add required packages

In /etc/nixos edit configuration.nix

  imports =
    [  # ...
      ./ldapserver.nix
    ];

  environment.systemPackages = with pkgs; [
    nix-repl wget mc tmux htop freeradius openldap
  ];

  networking.firewall.allowedTCPPorts = [ 389 ];
  networking.firewall.allowedUDPPorts = [ 1812 ];

  # Optionally:
  #networking.firewall.enable = false;
  #networking.firewall.allowPing = true;
  1. Configure OpenLDAP and FreeRadius

/etc/nixos/ldapserver.nix

{ pkgs, config, ... }:
let
  dbPath = "/var/db/openldap";
in
{
  imports = [
    <nixpkgs/nixos/modules/profiles/headless.nix>
    <nixpkgs/nixos/modules/services/networking/freeradius.nix>
  ];

  security.sudo.enable = true;

  services.freeradius.enable = true;
  services.openldap.enable = true;
  services.openldap.dataDir = "${dbPath}";
  services.openldap.extraConfig = ''
    include ${pkgs.openldap.out}/etc/schema/core.schema
    include ${pkgs.openldap.out}/etc/schema/cosine.schema
    include ${pkgs.openldap.out}/etc/schema/inetorgperson.schema
    include ${pkgs.openldap.out}/etc/schema/nis.schema
    include ${pkgs.freeradius.out}/share/doc/freeradius/schemas/ldap/openldap/freeradius.schema
    include /etc/nixos/samba.schema

    database mdb
    suffix dc=mycompany,dc=com
    rootdn cn=root,dc=mycompany,dc=com
    directory ${dbPath}

    index       objectClass eq
    rootpw      INITIALLDAPADMINPASSWORD
  '';
}
  1. Copy samba.schema into /etc/nixos
##
## schema file for OpenLDAP 2.x
## Schema for storing Samba user accounts and group maps in LDAP
## OIDs are owned by the Samba Team
##
## Prerequisite schemas - uid         (cosine.schema)
##                      - displayName (inetorgperson.schema)
##                      - gidNumber   (nis.schema)
##
## 1.3.6.1.4.1.7165.2.1.x - attributetypes
## 1.3.6.1.4.1.7165.2.2.x - objectclasses
##
## Printer support
## 1.3.6.1.4.1.7165.2.3.1.x - attributetypes
## 1.3.6.1.4.1.7165.2.3.2.x - objectclasses
##
## Samba4
## 1.3.6.1.4.1.7165.4.1.x - attributetypes
## 1.3.6.1.4.1.7165.4.2.x - objectclasses
## 1.3.6.1.4.1.7165.4.3.x - LDB/LDAP Controls
## 1.3.6.1.4.1.7165.4.4.x - LDB/LDAP Extended Operations
## 1.3.6.1.4.1.7165.4.255.x - mapped OIDs due to conflicts between AD and standards-track
##
## External projects
## 1.3.6.1.4.1.7165.655.x
## 1.3.6.1.4.1.7165.655.1.x - GSS-NTLMSSP
##
## ----- READ THIS WHEN ADDING A NEW ATTRIBUTE OR OBJECT CLASS ------
##
## Run the 'get_next_oid' bash script in this directory to find the
## next available OID for attribute type and object classes.
##
##   $ ./get_next_oid
##   attributetype ( 1.3.6.1.4.1.7165.2.1.XX NAME ....
##   objectclass ( 1.3.6.1.4.1.7165.2.2.XX NAME ....
##
## Also ensure that new entries adhere to the declaration style
## used throughout this file
##
##    <attributetype|objectclass> ( 1.3.6.1.4.1.7165.2.XX.XX NAME ....
##                               ^ ^                        ^
##
## The spaces are required for the get_next_oid script (and for
## readability).
##
## ------------------------------------------------------------------

# objectIdentifier SambaRoot 1.3.6.1.4.1.7165
# objectIdentifier Samba3 SambaRoot:2
# objectIdentifier Samba3Attrib Samba3:1
# objectIdentifier Samba3ObjectClass Samba3:2
# objectIdentifier Samba4 SambaRoot:4

########################################################################
##                            HISTORICAL                              ##
########################################################################

##
## Password hashes
##
#attributetype ( 1.3.6.1.4.1.7165.2.1.1 NAME 'lmPassword'
#   DESC 'LanManager Passwd'
#   EQUALITY caseIgnoreIA5Match
#   SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{32} SINGLE-VALUE )

#attributetype ( 1.3.6.1.4.1.7165.2.1.2 NAME 'ntPassword'
#   DESC 'NT Passwd'
#   EQUALITY caseIgnoreIA5Match
#   SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{32} SINGLE-VALUE )

##
## Account flags in string format ([UWDX     ])
##
#attributetype ( 1.3.6.1.4.1.7165.2.1.4 NAME 'acctFlags'
#   DESC 'Account Flags'
#   EQUALITY caseIgnoreIA5Match
#   SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{16} SINGLE-VALUE )

##
## Password timestamps & policies
##
#attributetype ( 1.3.6.1.4.1.7165.2.1.3 NAME 'pwdLastSet'
#   DESC 'NT pwdLastSet'
#   EQUALITY integerMatch
#   SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )

#attributetype ( 1.3.6.1.4.1.7165.2.1.5 NAME 'logonTime'
#   DESC 'NT logonTime'
#   EQUALITY integerMatch
#   SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )

#attributetype ( 1.3.6.1.4.1.7165.2.1.6 NAME 'logoffTime'
#   DESC 'NT logoffTime'
#   EQUALITY integerMatch
#   SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )

#attributetype ( 1.3.6.1.4.1.7165.2.1.7 NAME 'kickoffTime'
#   DESC 'NT kickoffTime'
#   EQUALITY integerMatch
#   SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )

#attributetype ( 1.3.6.1.4.1.7165.2.1.8 NAME 'pwdCanChange'
#   DESC 'NT pwdCanChange'
#   EQUALITY integerMatch
#   SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )

#attributetype ( 1.3.6.1.4.1.7165.2.1.9 NAME 'pwdMustChange'
#   DESC 'NT pwdMustChange'
#   EQUALITY integerMatch
#   SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )

##
## string settings
##
#attributetype ( 1.3.6.1.4.1.7165.2.1.10 NAME 'homeDrive'
#   DESC 'NT homeDrive'
#   EQUALITY caseIgnoreIA5Match
#   SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{4} SINGLE-VALUE )

#attributetype ( 1.3.6.1.4.1.7165.2.1.11 NAME 'scriptPath'
#   DESC 'NT scriptPath'
#   EQUALITY caseIgnoreIA5Match
#   SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{255} SINGLE-VALUE )

#attributetype ( 1.3.6.1.4.1.7165.2.1.12 NAME 'profilePath'
#   DESC 'NT profilePath'
#   EQUALITY caseIgnoreIA5Match
#   SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{255} SINGLE-VALUE )

#attributetype ( 1.3.6.1.4.1.7165.2.1.13 NAME 'userWorkstations'
#   DESC 'userWorkstations'
#   EQUALITY caseIgnoreIA5Match
#   SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{255} SINGLE-VALUE )

#attributetype ( 1.3.6.1.4.1.7165.2.1.17 NAME 'smbHome'
#   DESC 'smbHome'
#   EQUALITY caseIgnoreIA5Match
#   SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{128} )

#attributetype ( 1.3.6.1.4.1.7165.2.1.18 NAME 'domain'
#   DESC 'Windows NT domain to which the user belongs'
#   EQUALITY caseIgnoreIA5Match
#   SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{128} )

##
## user and group RID
##
#attributetype ( 1.3.6.1.4.1.7165.2.1.14 NAME 'rid'
#   DESC 'NT rid'
#   EQUALITY integerMatch
#   SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )

#attributetype ( 1.3.6.1.4.1.7165.2.1.15 NAME 'primaryGroupID'
#   DESC 'NT Group RID'
#   EQUALITY integerMatch
#   SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )

##
## The smbPasswordEntry objectclass has been depreciated in favor of the
## sambaAccount objectclass
##
#objectclass ( 1.3.6.1.4.1.7165.2.2.1 NAME 'smbPasswordEntry' SUP top AUXILIARY
#        DESC 'Samba smbpasswd entry'
#        MUST ( uid $ uidNumber )
#        MAY  ( lmPassword $ ntPassword $ pwdLastSet $ acctFlags ))

#objectclass ( 1.3.6.1.4.1.7165.2.2.2 NAME 'sambaAccount' SUP top STRUCTURAL
#   DESC 'Samba Account'
#   MUST ( uid $ rid )
#   MAY  ( cn $ lmPassword $ ntPassword $ pwdLastSet $ logonTime $
#               logoffTime $ kickoffTime $ pwdCanChange $ pwdMustChange $ acctFlags $
#               displayName $ smbHome $ homeDrive $ scriptPath $ profilePath $
#               description $ userWorkstations $ primaryGroupID $ domain ))

#objectclass ( 1.3.6.1.4.1.7165.2.2.3 NAME 'sambaAccount' SUP top AUXILIARY
#   DESC 'Samba Auxiliary Account'
#   MUST ( uid $ rid )
#   MAY  ( cn $ lmPassword $ ntPassword $ pwdLastSet $ logonTime $
#              logoffTime $ kickoffTime $ pwdCanChange $ pwdMustChange $ acctFlags $
#              displayName $ smbHome $ homeDrive $ scriptPath $ profilePath $
#              description $ userWorkstations $ primaryGroupID $ domain ))

########################################################################
##                        END OF HISTORICAL                           ##
########################################################################

#######################################################################
##                Attributes used by Samba 3.0 schema                ##
#######################################################################

##
## Password hashes
##
attributetype ( 1.3.6.1.4.1.7165.2.1.24 NAME 'sambaLMPassword'
    DESC 'LanManager Password'
    EQUALITY caseIgnoreIA5Match
    SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{32} SINGLE-VALUE )

attributetype ( 1.3.6.1.4.1.7165.2.1.25 NAME 'sambaNTPassword'
    DESC 'MD4 hash of the unicode password'
    EQUALITY caseIgnoreIA5Match
    SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{32} SINGLE-VALUE )

##
## Account flags in string format ([UWDX     ])
##
attributetype ( 1.3.6.1.4.1.7165.2.1.26 NAME 'sambaAcctFlags'
    DESC 'Account Flags'
    EQUALITY caseIgnoreIA5Match
    SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{16} SINGLE-VALUE )

##
## Password timestamps & policies
##
attributetype ( 1.3.6.1.4.1.7165.2.1.27 NAME 'sambaPwdLastSet'
    DESC 'Timestamp of the last password update'
    EQUALITY integerMatch
    SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )

attributetype ( 1.3.6.1.4.1.7165.2.1.28 NAME 'sambaPwdCanChange'
    DESC 'Timestamp of when the user is allowed to update the password'
    EQUALITY integerMatch
    SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )

attributetype ( 1.3.6.1.4.1.7165.2.1.29 NAME 'sambaPwdMustChange'
    DESC 'Timestamp of when the password will expire'
    EQUALITY integerMatch
    SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )

attributetype ( 1.3.6.1.4.1.7165.2.1.30 NAME 'sambaLogonTime'
    DESC 'Timestamp of last logon'
    EQUALITY integerMatch
    SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )

attributetype ( 1.3.6.1.4.1.7165.2.1.31 NAME 'sambaLogoffTime'
    DESC 'Timestamp of last logoff'
    EQUALITY integerMatch
    SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )

attributetype ( 1.3.6.1.4.1.7165.2.1.32 NAME 'sambaKickoffTime'
    DESC 'Timestamp of when the user will be logged off automatically'
    EQUALITY integerMatch
    SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )

attributetype ( 1.3.6.1.4.1.7165.2.1.48 NAME 'sambaBadPasswordCount'
    DESC 'Bad password attempt count'
    EQUALITY integerMatch
    SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )

attributetype ( 1.3.6.1.4.1.7165.2.1.49 NAME 'sambaBadPasswordTime'
    DESC 'Time of the last bad password attempt'
    EQUALITY integerMatch
    SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )

attributetype ( 1.3.6.1.4.1.7165.2.1.55 NAME 'sambaLogonHours'
    DESC 'Logon Hours'
    EQUALITY caseIgnoreIA5Match
    SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{42} SINGLE-VALUE )

##
## string settings
##
attributetype ( 1.3.6.1.4.1.7165.2.1.33 NAME 'sambaHomeDrive'
    DESC 'Driver letter of home directory mapping'
    EQUALITY caseIgnoreIA5Match
    SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{4} SINGLE-VALUE )

attributetype ( 1.3.6.1.4.1.7165.2.1.34 NAME 'sambaLogonScript'
    DESC 'Logon script path'
    EQUALITY caseIgnoreMatch
    SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{255} SINGLE-VALUE )

attributetype ( 1.3.6.1.4.1.7165.2.1.35 NAME 'sambaProfilePath'
    DESC 'Roaming profile path'
    EQUALITY caseIgnoreMatch
    SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{255} SINGLE-VALUE )

attributetype ( 1.3.6.1.4.1.7165.2.1.36 NAME 'sambaUserWorkstations'
    DESC 'List of user workstations the user is allowed to logon to'
    EQUALITY caseIgnoreMatch
    SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{255} SINGLE-VALUE )

attributetype ( 1.3.6.1.4.1.7165.2.1.37 NAME 'sambaHomePath'
    DESC 'Home directory UNC path'
    EQUALITY caseIgnoreMatch
    SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} )

attributetype ( 1.3.6.1.4.1.7165.2.1.38 NAME 'sambaDomainName'
    DESC 'Windows NT domain to which the user belongs'
    EQUALITY caseIgnoreMatch
    SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} )

attributetype ( 1.3.6.1.4.1.7165.2.1.47 NAME 'sambaMungedDial'
    DESC 'Base64 encoded user parameter string'
    EQUALITY caseExactMatch
    SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1050} )

attributetype ( 1.3.6.1.4.1.7165.2.1.54 NAME 'sambaPasswordHistory'
    DESC 'Concatenated MD5 hashes of the salted NT passwords used on this account'
    EQUALITY caseIgnoreIA5Match
    SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{32} )

##
## SID, of any type
##

attributetype ( 1.3.6.1.4.1.7165.2.1.20 NAME 'sambaSID'
    DESC 'Security ID'
    EQUALITY caseIgnoreIA5Match
    SUBSTR caseExactIA5SubstringsMatch
    SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{64} SINGLE-VALUE )

##
## Primary group SID, compatible with ntSid
##

attributetype ( 1.3.6.1.4.1.7165.2.1.23 NAME 'sambaPrimaryGroupSID'
    DESC 'Primary Group Security ID'
    EQUALITY caseIgnoreIA5Match
    SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{64} SINGLE-VALUE )

attributetype ( 1.3.6.1.4.1.7165.2.1.51 NAME 'sambaSIDList'
    DESC 'Security ID List'
    EQUALITY caseIgnoreIA5Match
    SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{64} )

##
## group mapping attributes
##
attributetype ( 1.3.6.1.4.1.7165.2.1.19 NAME 'sambaGroupType'
    DESC 'NT Group Type'
    EQUALITY integerMatch
    SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )

##
## Store info on the domain
##

attributetype ( 1.3.6.1.4.1.7165.2.1.21 NAME 'sambaNextUserRid'
    DESC 'Next NT rid to give our for users'
    EQUALITY integerMatch
    SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )

attributetype ( 1.3.6.1.4.1.7165.2.1.22 NAME 'sambaNextGroupRid'
    DESC 'Next NT rid to give out for groups'
    EQUALITY integerMatch
    SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )

attributetype ( 1.3.6.1.4.1.7165.2.1.39 NAME 'sambaNextRid'
    DESC 'Next NT rid to give out for anything'
    EQUALITY integerMatch
    SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )

attributetype ( 1.3.6.1.4.1.7165.2.1.40 NAME 'sambaAlgorithmicRidBase'
    DESC 'Base at which the samba RID generation algorithm should operate'
    EQUALITY integerMatch
    SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )

attributetype ( 1.3.6.1.4.1.7165.2.1.41 NAME 'sambaShareName'
    DESC 'Share Name'
    EQUALITY caseIgnoreMatch
    SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )

attributetype ( 1.3.6.1.4.1.7165.2.1.42 NAME 'sambaOptionName'
    DESC 'Option Name'
    EQUALITY caseIgnoreMatch
    SUBSTR caseIgnoreSubstringsMatch
    SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )

attributetype ( 1.3.6.1.4.1.7165.2.1.43 NAME 'sambaBoolOption'
    DESC 'A boolean option'
    EQUALITY booleanMatch
    SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE )

attributetype ( 1.3.6.1.4.1.7165.2.1.44 NAME 'sambaIntegerOption'
    DESC 'An integer option'
    EQUALITY integerMatch
    SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )

attributetype ( 1.3.6.1.4.1.7165.2.1.45 NAME 'sambaStringOption'
    DESC 'A string option'
    EQUALITY caseExactIA5Match
    SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )

attributetype ( 1.3.6.1.4.1.7165.2.1.46 NAME 'sambaStringListOption'
    DESC 'A string list option'
    EQUALITY caseIgnoreMatch
    SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )


##attributetype ( 1.3.6.1.4.1.7165.2.1.50 NAME 'sambaPrivName'
##  SUP name )

##attributetype ( 1.3.6.1.4.1.7165.2.1.52 NAME 'sambaPrivilegeList'
##  DESC 'Privileges List'
##  EQUALITY caseIgnoreIA5Match
##  SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{64} )

attributetype ( 1.3.6.1.4.1.7165.2.1.53 NAME 'sambaTrustFlags'
    DESC 'Trust Password Flags'
    EQUALITY caseIgnoreIA5Match
    SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )

# "min password length"
attributetype ( 1.3.6.1.4.1.7165.2.1.58 NAME 'sambaMinPwdLength'
    DESC 'Minimal password length (default: 5)'
    EQUALITY integerMatch
    SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )

# "password history"
attributetype ( 1.3.6.1.4.1.7165.2.1.59 NAME 'sambaPwdHistoryLength'
    DESC 'Length of Password History Entries (default: 0 => off)'
    EQUALITY integerMatch
    SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )

# "user must logon to change password"
attributetype ( 1.3.6.1.4.1.7165.2.1.60 NAME 'sambaLogonToChgPwd'
    DESC 'Force Users to logon for password change (default: 0 => off, 2 => on)'
    EQUALITY integerMatch
    SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )

# "maximum password age"
attributetype ( 1.3.6.1.4.1.7165.2.1.61 NAME 'sambaMaxPwdAge'
    DESC 'Maximum password age, in seconds (default: -1 => never expire passwords)'
    EQUALITY integerMatch
    SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )

# "minimum password age"
attributetype ( 1.3.6.1.4.1.7165.2.1.62 NAME 'sambaMinPwdAge'
    DESC 'Minimum password age, in seconds (default: 0 => allow immediate password change)'
    EQUALITY integerMatch
    SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )

# "lockout duration"
attributetype ( 1.3.6.1.4.1.7165.2.1.63 NAME 'sambaLockoutDuration'
    DESC 'Lockout duration in minutes (default: 30, -1 => forever)'
    EQUALITY integerMatch
    SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )

# "reset count minutes"
attributetype ( 1.3.6.1.4.1.7165.2.1.64 NAME 'sambaLockoutObservationWindow'
    DESC 'Reset time after lockout in minutes (default: 30)'
    EQUALITY integerMatch
    SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )

# "bad lockout attempt"
attributetype ( 1.3.6.1.4.1.7165.2.1.65 NAME 'sambaLockoutThreshold'
    DESC 'Lockout users after bad logon attempts (default: 0 => off)'
    EQUALITY integerMatch
    SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )

# "disconnect time"
attributetype ( 1.3.6.1.4.1.7165.2.1.66 NAME 'sambaForceLogoff'
    DESC 'Disconnect Users outside logon hours (default: -1 => off, 0 => on)'
    EQUALITY integerMatch
    SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )

# "refuse machine password change"
attributetype ( 1.3.6.1.4.1.7165.2.1.67 NAME 'sambaRefuseMachinePwdChange'
    DESC 'Allow Machine Password changes (default: 0 => off)'
    EQUALITY integerMatch
    SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )

#
attributetype ( 1.3.6.1.4.1.7165.2.1.68 NAME 'sambaClearTextPassword'
    DESC 'Clear text password (used for trusted domain passwords)'
    EQUALITY octetStringMatch
    SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )

#
attributetype ( 1.3.6.1.4.1.7165.2.1.69 NAME 'sambaPreviousClearTextPassword'
    DESC 'Previous clear text password (used for trusted domain passwords)'
    EQUALITY octetStringMatch
    SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )

attributetype ( 1.3.6.1.4.1.7165.2.1.70 NAME 'sambaTrustType'
    DESC 'Type of trust'
    EQUALITY integerMatch
    SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )

attributetype ( 1.3.6.1.4.1.7165.2.1.71 NAME 'sambaTrustAttributes'
    DESC 'Trust attributes for a trusted domain'
    EQUALITY integerMatch
    SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )

attributetype ( 1.3.6.1.4.1.7165.2.1.72 NAME 'sambaTrustDirection'
    DESC 'Direction of a trust'
    EQUALITY integerMatch
    SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )

attributetype ( 1.3.6.1.4.1.7165.2.1.73 NAME 'sambaTrustPartner'
    DESC 'Fully qualified name of the domain with which a trust exists'
    EQUALITY caseIgnoreMatch
    SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} )

attributetype ( 1.3.6.1.4.1.7165.2.1.74 NAME 'sambaFlatName'
    DESC 'NetBIOS name of a domain'
    EQUALITY caseIgnoreMatch
    SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} )

attributetype ( 1.3.6.1.4.1.7165.2.1.75 NAME 'sambaTrustAuthOutgoing'
    DESC 'Authentication information for the outgoing portion of a trust'
    EQUALITY caseExactMatch
    SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1050} )

attributetype ( 1.3.6.1.4.1.7165.2.1.76 NAME 'sambaTrustAuthIncoming'
    DESC 'Authentication information for the incoming portion of a trust'
    EQUALITY caseExactMatch
    SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1050} )

attributetype ( 1.3.6.1.4.1.7165.2.1.77 NAME 'sambaSecurityIdentifier'
    DESC 'SID of a trusted domain'
    EQUALITY caseIgnoreIA5Match SUBSTR caseExactIA5SubstringsMatch
    SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{64} SINGLE-VALUE )

attributetype ( 1.3.6.1.4.1.7165.2.1.78 NAME 'sambaTrustForestTrustInfo'
    DESC 'Forest trust information for a trusted domain object'
    EQUALITY caseExactMatch
    SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1050} )

attributetype ( 1.3.6.1.4.1.7165.2.1.79 NAME 'sambaTrustPosixOffset'
    DESC 'POSIX offset of a trust'
    EQUALITY integerMatch
    SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )

attributetype ( 1.3.6.1.4.1.7165.2.1.80 NAME 'sambaSupportedEncryptionTypes'
    DESC 'Supported encryption types of a trust'
    EQUALITY integerMatch
    SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )

#######################################################################
##              objectClasses used by Samba 3.0 schema               ##
#######################################################################

## The X.500 data model (and therefore LDAPv3) says that each entry can
## only have one structural objectclass.  OpenLDAP 2.0 does not enforce
## this currently but will in v2.1

##
## added new objectclass (and OID) for 3.0 to help us deal with backwards
## compatibility with 2.2 installations (e.g. ldapsam_compat)  --jerry
##
objectclass ( 1.3.6.1.4.1.7165.2.2.6 NAME 'sambaSamAccount' SUP top AUXILIARY
    DESC 'Samba 3.0 Auxilary SAM Account'
    MUST ( uid $ sambaSID )
    MAY  ( cn $ sambaLMPassword $ sambaNTPassword $ sambaPwdLastSet $
           sambaLogonTime $ sambaLogoffTime $ sambaKickoffTime $
           sambaPwdCanChange $ sambaPwdMustChange $ sambaAcctFlags $
               displayName $ sambaHomePath $ sambaHomeDrive $ sambaLogonScript $
           sambaProfilePath $ description $ sambaUserWorkstations $
           sambaPrimaryGroupSID $ sambaDomainName $ sambaMungedDial $
           sambaBadPasswordCount $ sambaBadPasswordTime $
           sambaPasswordHistory $ sambaLogonHours))

##
## Group mapping info
##
objectclass ( 1.3.6.1.4.1.7165.2.2.4 NAME 'sambaGroupMapping' SUP top AUXILIARY
    DESC 'Samba Group Mapping'
    MUST ( gidNumber $ sambaSID $ sambaGroupType )
    MAY  ( displayName $ description $ sambaSIDList ))

##
## Trust password for trust relationships (any kind)
##
objectclass ( 1.3.6.1.4.1.7165.2.2.14 NAME 'sambaTrustPassword' SUP top STRUCTURAL
    DESC 'Samba Trust Password'
    MUST ( sambaDomainName $ sambaNTPassword $ sambaTrustFlags )
    MAY ( sambaSID $ sambaPwdLastSet ))

##
## Trust password for trusted domains
## (to be stored beneath the trusting sambaDomain object in the DIT)
##
objectclass ( 1.3.6.1.4.1.7165.2.2.15 NAME 'sambaTrustedDomainPassword' SUP top STRUCTURAL
    DESC 'Samba Trusted Domain Password'
    MUST ( sambaDomainName $ sambaSID $
           sambaClearTextPassword $ sambaPwdLastSet )
    MAY  ( sambaPreviousClearTextPassword ))

##
## Whole-of-domain info
##
objectclass ( 1.3.6.1.4.1.7165.2.2.5 NAME 'sambaDomain' SUP top STRUCTURAL
    DESC 'Samba Domain Information'
    MUST ( sambaDomainName $
           sambaSID )
    MAY ( sambaNextRid $ sambaNextGroupRid $ sambaNextUserRid $
          sambaAlgorithmicRidBase $
          sambaMinPwdLength $ sambaPwdHistoryLength $ sambaLogonToChgPwd $
          sambaMaxPwdAge $ sambaMinPwdAge $
          sambaLockoutDuration $ sambaLockoutObservationWindow $ sambaLockoutThreshold $
          sambaForceLogoff $ sambaRefuseMachinePwdChange ))

##
## used for idmap_ldap module
##
objectclass ( 1.3.6.1.4.1.7165.2.2.7 NAME 'sambaUnixIdPool' SUP top AUXILIARY
        DESC 'Pool for allocating UNIX uids/gids'
        MUST ( uidNumber $ gidNumber ) )


objectclass ( 1.3.6.1.4.1.7165.2.2.8 NAME 'sambaIdmapEntry' SUP top AUXILIARY
        DESC 'Mapping from a SID to an ID'
        MUST ( sambaSID )
    MAY ( uidNumber $ gidNumber ) )

objectclass ( 1.3.6.1.4.1.7165.2.2.9 NAME 'sambaSidEntry' SUP top STRUCTURAL
    DESC 'Structural Class for a SID'
    MUST ( sambaSID ) )

objectclass ( 1.3.6.1.4.1.7165.2.2.10 NAME 'sambaConfig' SUP top AUXILIARY
    DESC 'Samba Configuration Section'
    MAY ( description ) )

objectclass ( 1.3.6.1.4.1.7165.2.2.11 NAME 'sambaShare' SUP top STRUCTURAL
    DESC 'Samba Share Section'
    MUST ( sambaShareName )
    MAY ( description ) )

objectclass ( 1.3.6.1.4.1.7165.2.2.12 NAME 'sambaConfigOption' SUP top STRUCTURAL
    DESC 'Samba Configuration Option'
    MUST ( sambaOptionName )
    MAY ( sambaBoolOption $ sambaIntegerOption $ sambaStringOption $
          sambaStringListoption $ description ) )


## retired during privilege rewrite
##objectclass ( 1.3.6.1.4.1.7165.2.2.13 NAME 'sambaPrivilege' SUP top AUXILIARY
##  DESC 'Samba Privilege'
##  MUST ( sambaSID )
##  MAY ( sambaPrivilegeList ) )

##
## used for IPA_ldapsam
##
objectclass ( 1.3.6.1.4.1.7165.2.2.16 NAME 'sambaTrustedDomain' SUP top STRUCTURAL
    DESC 'Samba Trusted Domain Object'
    MUST ( cn )
    MAY ( sambaTrustType $ sambaTrustAttributes $ sambaTrustDirection $
          sambaTrustPartner $ sambaFlatName $ sambaTrustAuthOutgoing $
          sambaTrustAuthIncoming $ sambaSecurityIdentifier $
          sambaTrustForestTrustInfo $ sambaTrustPosixOffset $
          sambaSupportedEncryptionTypes) )
  1. Install and initialize services
nix-rebuild switch
ldapadd -x -W -D "cn=root,dc=mycompany,dc=com" -f basic.ldif
  1. Configure Radius
  • Find radius distro location: ls -la /nix/store | grep radius
  • copy radius config: cp $RADIUS_BASE/etc/raddb /etc/

/etc/raddb/clients.conf (just replace this file)

client localhost {
    ipaddr = 127.0.0.1
    proto = *
    secret = RANDOMSTRING
    require_message_authenticator = no
    nas_type     = other    # localhost isn't usually a NAS...
    limit {
        max_connections = 16
        lifetime = 0
        idle_timeout = 30
    }
}

/etc/raddb/mods-available/ldap (just replace this file)

ldap {
server = "auth.mycompany.com"
identity = "cn=root,dc=mycompany,dc=com"
password = "INITIALLDAPADMINPASSWORD"

base_dn = "dc=SMBDOMAIN,dc=mycompany,dc=com"

user {
  base_dn = "${..base_dn}"
  filter = "(uid=%{%{Stripped-User-Name}:-%{User-Name}})"
}

update {
  #control:Password-With-Header += 'userPassword'
  control:NT-Password := 'sambaNTPassword'
}

}

/etc/raddb/sites-available/myorg

server mycompany {
client private-network-2 {
    ipaddr      = 192.168.10.0/24
    secret      = RADIUSSECRET
}
client private-network-3 {
    ipaddr      = 127.0.0.0/24
    secret      = RADIUSSECRET
}

listen {
       ipaddr = 0.0.0.0
       port = 0
       type = auth
}
authorize {
    filter_username
    #chap
    mschap
    suffix
    update control {
        &Proxy-To-Realm := LOCAL
    }
    eap {
        ok = return
    }
    #files
    #-sql
    ldap
    expiration
    logintime
    pap
}
authenticate {
    Auth-Type PAP {
        pap
    }
    #Auth-Type CHAP {
    #   chap
    #}
    Auth-Type MS-CHAP {
        mschap
    }
    mschap
    #Auth-Type LDAP {
    #   ldap
    #}
    eap
}
session {
    radutmp
}
post-auth {
    -sql
    if (0) {
        update reply {
            User-Name !* ANY
            Message-Authenticator !* ANY
            EAP-Message !* ANY
            Proxy-State !* ANY
            MS-MPPE-Encryption-Types !* ANY
            MS-MPPE-Encryption-Policy !* ANY
            MS-MPPE-Send-Key !* ANY
            MS-MPPE-Recv-Key !* ANY
        }
        update {
            &outer.session-state: += &reply:
        }
    }
    Post-Auth-Type REJECT {
        -sql
        attr_filter.access_reject
        update outer.session-state {
            &Module-Failure-Message := &request:Module-Failure-Message
        }
    }
}
pre-proxy {
}
post-proxy {
    eap
}
} # inner-tunnel server block

/etc/raddb/sites-available/inner-tunnel (just replace this file)

server inner-tunnel {
listen {
       ipaddr = 127.0.0.1
       port = 18120
       type = auth
}
authorize {
    filter_username
    mschap
    suffix
    update control {
        &Proxy-To-Realm := LOCAL
    }
    eap {
        ok = return
    }
    #files
    #-sql
    ldap
    expiration
    logintime
    pap
}
authenticate {
    Auth-Type PAP {
        pap
    }
    Auth-Type MS-CHAP {
        mschap
    }
    mschap
    #Auth-Type LDAP {
    #   ldap
    #}
    eap
}
session {
    radutmp
}
post-auth {
    -sql
    if (0) {
        update reply {
            User-Name !* ANY
            Message-Authenticator !* ANY
            EAP-Message !* ANY
            Proxy-State !* ANY
            MS-MPPE-Encryption-Types !* ANY
            MS-MPPE-Encryption-Policy !* ANY
            MS-MPPE-Send-Key !* ANY
            MS-MPPE-Recv-Key !* ANY
        }
        update {
            &outer.session-state: += &reply:
        }
    }
    Post-Auth-Type REJECT {
        -sql
        attr_filter.access_reject
        update outer.session-state {
            &Module-Failure-Message := &request:Module-Failure-Message
        }
    }
}
pre-proxy {
}
post-proxy {
    eap
}
} # inner-tunnel server block
  • cd into sites-enabled, remove all the symlinks and ln -s ../sites-available/myorg myorg ln -s ../sites-available/inner-tunnel inner-tunnel
  • systemctl restart freeradius

The only thing left is to configure Samba with smbldap-tools, after that we will be able to use our LDAP installation for:

  • WPA Enterprise Wi-Fi
  • L2TP VPN
  • Linux PAM authorization

Samba configuration

/etc/samba/smb.conf

[global]
   passdb backend = ldapsam:ldap://auth.mycompany.com
   ldap suffix = dc=mycompany,dc=com
   ldap admin dn = cn=root,dc=mycompany,dc=com
   ldap server require strong auth = no
   ldap ssl = off

    load printers = no
    printing = bsd
    printcap name = /dev/null
    disable spoolss = yes

   workgroup = SMBDOMAIN
   server string = AUTH
   server role = classic primary domain controller
   map to guest = bad user
   log file = /var/log/samba/log.%m
   max log size = 50
   dns proxy = no
   security = user
  • Invoke smbpasswd -w ADMINPASSWORD and type INITIALLDAPADMINPASSWORD from above
  • Use net join to join domain, in case of issues use net getlocalsid and net getdomainsid, the output should match. In case it doesn't use net setlocalsid DOMAINSID
  • smbcontrol smbd debug 10 may help to debug any issues

smbldap-tools

  • Install em
  • edit /etc/smbldap-tools/smbldap_bind.conf, put your root user credentials for both master and slave entries
  • edit /etc/smbldap-tools/smbldap.conf
SID="XXXXXXXXXXXXXXXXXXXXX" # use output of `net getdomainsid`
sambaDomain="SMBDOMAIN"
slaveLDAP="auth.mycompany.com"
slavePort="389"
masterLDAP="auth.mycompany.com"
masterPort="389"
ldapTLS="0"
ldapSSL="0"
verify="require"
cafile="/etc/smbldap-tools/ca.pem"
clientcert="/etc/smbldap-tools/smbldap-tools.example.com.pem"
clientkey="/etc/smbldap-tools/smbldap-tools.example.com.key"
suffix="dc=SMBDOMAIN,dc=mycompany,dc=com"
usersdn="ou=Users,${suffix}"
computersdn="ou=Computers,${suffix}"
groupsdn="ou=Groups,${suffix}"
idmapdn="ou=Idmap,${suffix}"
sambaUnixIdPooldn="sambaDomainName=${sambaDomain},${suffix}"
scope="sub"
password_hash="SSHA"
password_crypt_salt_format="%s"
userLoginShell="/bin/bash"
userHome="/home/%U"
userHomeDirectoryMode="700"
userGecos="System User"
defaultUserGid="513"
defaultComputerGid="515"
skeletonDir="/etc/skel"
shadowAccount="1"
defaultMaxPasswordAge="45"
userSmbHome="\\nas\%U"
userProfile="\\nas\profiles\%U"
userHomeDrive="H:"
userScript="logon.bat"
mailDomain="example.com"
with_smbpasswd="0"
smbpasswd="/usr/bin/smbpasswd"
with_slappasswd="0"
slappasswd="/usr/sbin/slappasswd"
  • smbldap-populate
  • smbldap -a user
  • smbpasswd user

Now the user should be able to use radius authorization. We may setup a box allowing any user to login and invoke smbpasswd for self-service purposes.

Useful debug command:

radtest -t mschap user passw auth.mycompany.com 0 RADIUSSECRET

PAM radius authorization

  • Depends on your distro
  • Usually we would have to install PAM radius module, then add the following line at the top of /etc/pam.d/system-auth:
auth            sufficient      pam_radius_auth.so
  • Now we need to edit /etc/raddb/server:
auth.mycompany.com   RADIUSSECRET 1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment