Настройка Proftpd для Samba 4 server в режиме domain controller через ldap.
Предполагается, что у вас установлена и настроена samba 4 server в режиме active directory domain controller.
Установлен proftpd с поддержкой ldap.
В AD созданы 3 пользователя:
1. ldap_user – обычный (без привелегий) пользователь от которого будем производить поиск в LDAP с паролем User_123
2. user1
3. user2
В AD созданы 2 группы ftp1 и ftp2.
2 группы нам понадобятся исключительно для наглядной иллюстрации работы фильтра. В реальной ситуации достаточно 1-ой.
user1 входит в обе группы (ftp1 и ftp2)
user2 только в одну из них, допустим только в ftp1
Domain name: test.loc
Hostname: pdc.test.loc
На файловой системе создана директория /share/ftp
Заглянем в /etc/proftpd.conf изменим/добавим необходимые для нашей задачи строки:
LoadModule mod_ldap.c # подгружаем модуль LDAP
…
RequireValidShell no # пока не отменил данную проверку shell, proftpd отказывался меня авторизовывать.
…
# Use pam to authenticate (default) and be authoritative
AuthPAMConfig proftpd
#AuthOrder mod_auth_pam.c* mod_auth_unix.c
AuthOrder mod_ldap.c # добавляем авторизацию через ldap
PersistentPasswd off
…
# Use this to excude users from the chroot
#DefaultRoot ~ !adm
DefaultRoot /share/ftp/%u # Помещение пользователя в chroot. Ограничение корневого уровня, выше которого пользователь не сможет подняться. В данном случае пользователь имеет возможность находиться только в пределах своей директории (homedir).
…
#<IfModule mod_ldap.c> # 2-ой способ подгрузки модуля. В моей версии не заработал.
LDAPServer "pdc.test.loc" # адрес нашего LDAP сервера.
LDAPAttr uid SAMAccountname # LDAP атрибут
LDAPDNInfo "cn=ldap_user,cn=Users,dc=test,dc=loc" "User_123" #Существующий обычный (без привелегий) пользователь от которого будем производить поиск в LDAP
LDAPAuthBinds on
LDAPDoAuth on "cn=Users,dc=test,dc=loc" (&(sAMAccountname=%u)(objectClass=user)(memberOf=cn=ftp1,cn=users,dc=test,dc=loc)(memberOf=cn=ftp2,cn=users,dc=test,dc=loc)) #Наш «боевой» фильтр, в котором указано, что доступ к ftp получит только тот пользователь, который будет входить в обе группы ftp1 и ftp2. Фильтр ищет совпадение всех вышеперечисленных полей в LDAP (objectclass=значение)(memberOf=значение)(memberOf=значение). Если какого-то поля для пользователя не существует, например, потому, что он не является членом группы, то совпадения не будет, а, следовательно, в доступе будет отказано.
#LDAPDoAuth on "cn=Users,dc=test,dc=loc" (&(sAMAccountname=%u)(objectClass=top)(ObjectCategory=user)(objectclass=person)) #Еще один пример фильтра, который предоставит доступ к ftp любому существующему пользователю домена.
LDAPdoUIDLookups on "cn=Users,dc=test,dc=loc"
LDAPdoGIDLookups on "cn=Groups,dc=test,dc=loc"
LDAPDefaultUID 99 # Можно использовать любой UID, однако пока гуглил встретил описание «глюка» с upload файлов при UID 10000. Для своих целей взял nobody.
LDAPDefaultGID 99 # Можно так же использовать любой GID. Для своих целей взял nobody.
LDAPGenerateHomedir on #Создать homedir для пользователя
LDAPForceGeneratedHomedir on #Принудительно создать homedir для пользователя
LDAPGenerateHomedirPrefix /share/ftp #Префикс для homedir
#</IfModule>
…
# TLS #Включаем TLS.
# Explained at http://www.castaglia.org/proftpd/modules/mod_tls.html
TLSEngine on
TLSRequired off
TLSRSACertificateFile /etc/pki/tls/certs/proftpd.pem
TLSRSACertificateKeyFile /etc/pki/tls/certs/proftpd.pem
#TLSCipherSuite ALL:!ADH:!DES
TLSOptions NoCertRequest
TLSVerifyClient off
#TLSRenegotiate ctrl 3600 data 512000 required off timeout 300
TLSLog /var/log/proftpd/tls.log
TLSProtocol SSLv23
<Directory /share/ftp*> #Описание нашей директории
AllowOverwrite yes
<Limit ALL>
AllowAll
</Limit>
<Limit ALL SITE_CHMOD>
AllowAll
</Limit>
</Directory>
Не знаю насколько понятно объяснил про механизм работы фильтра. Для того, чтобы снять любые вопросы запустим из консоли следующую команду:
#ldapsearch -h localhost -W -x -D "cn=ldap_user,cn=Users,dc=test,dc=loc" -b "cn=Users,dc=test,dc=loc" sAMAccountName= user1
Enter LDAP Password:
# extended LDIF
#
# LDAPv3
# base <cn=Users,dc=test,dc=loc> with scope subtree
# filter: sAMAccountName=user1
# requesting: ALL
#
# user1, Users, test.loc
dn: CN=user1,CN=Users,DC=test,DC=loc
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: user
cn: user1
givenName: user1
instanceType: 4
whenCreated: 20130410135259.0Z
displayName: user1
uSNCreated: 5271
name: user1
objectGUID:: *****************
badPwdCount: 0
codePage: 0
countryCode: 0
badPasswordTime: 0
lastLogoff: 0
lastLogon: 0
primaryGroupID: 513
objectSid:: ********************************
accountExpires: 9223372036854775807
logonCount: 0
sAMAccountName: user1
sAMAccountType: 805306368
userPrincipalName: user1@test.loc
objectCategory: CN=Person,CN=Schema,CN=Configuration,DC=test,DC=loc
userAccountControl: 66048
pwdLastSet: 130101055070000000
whenChanged: 20130410221147.0Z
uSNChanged: 5276
memberOf: CN=ftp1,CN=Users,DC=test,DC=loc
memberOf: CN=ftp2,CN=Users,DC=test,DC=loc
distinguishedName: CN=user1,CN=Users,DC=test,DC=loc
# search result
search: 2
result: 0 Success
# numResponses: 2
# numEntries: 1
Как вы видите мы могли бы использовать для фильтра и другие поля. Например, вместо (objectclass=person) мы с тем же успехом могли использовать (objectClass=organizationalPerson) ну или (objectCategory=CN=Person,CN=Schema,CN=Configuration,DC=test,DC=loc)
Как я уже и говорил выше данный пользователь является членом 2-ух групп. Все поля запроса совпадают, поэтому доступ будет получен.
Теперь сделаем запрос из консоли для 2-ого пользователя user2:
#ldapsearch -h localhost -W -x -D "cn=ldap_user,cn=Users,dc=test,dc=loc" -b "cn=Users,dc=test,dc=loc" sAMAccountName= user2
Enter LDAP Password:
# extended LDIF
#
# LDAPv3
# base <cn=Users,dc=test,dc=loc> with scope subtree
# filter: sAMAccountName=user2
# requesting: ALL
#
# user2, Users, test.loc
dn: CN=user2,CN=Users,DC=test,DC=loc
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: user
cn: user2
givenName: user2
instanceType: 4
whenCreated: 20130509035833.0Z
displayName: user2
uSNCreated: 5297
name: user2
objectGUID:: ********************
badPwdCount: 0
codePage: 0
countryCode: 0
badPasswordTime: 0
lastLogoff: 0
lastLogon: 0
primaryGroupID: 513
objectSid:: *******************************
accountExpires: 9223372036854775807
logonCount: 0
sAMAccountName: user2
sAMAccountType: 805306368
userPrincipalName: user2@test.loc
objectCategory: CN=Person,CN=Schema,CN=Configuration,DC=test,DC=loc
pwdLastSet: 130125455140000000
userAccountControl: 66048
whenChanged: 20130509035835.0Z
uSNChanged: 5300
memberOf: CN=ftp1,CN=Users,DC=test,DC=loc
distinguishedName: CN=user2,CN=Users,DC=test,DC=loc
# search result
search: 2
result: 0 Success
# numResponses: 2
# numEntries: 1
Здесь мы видим, что пользователь входит только в одну группу, следовательно по шаблону (memberOf=CN=ftp2,CN=Users,DC=test,DC=loc) совпадения не будет, и пользователь доступ не получит. Если убрать эту запись из фильтра, то оба пользователя начнут получать доступ.
Настройка закончена. Теперь можно запускать proftpd и проверять работоспособность.
Для поиска проблем, можно запускать proftpd в режиме отладки с достаточным уровнем сообщений. Максимальный 10. Мне это помогло понять в каком месте конфигурационного файла я ошибся. Команда:
#proftpd --nodaemon --debug=10