FreeRADIUS 1.0.1 インストール (Solaris9 編)

Last update: 2004/11/27

1. 設定方針

ユーザアカウントはLDAPで管理
認証はPAP/MS-CHAP/MS-CHAPv2
アカウンティングはMySQLに格納

2. 認証の流れ

2-1. Authorize (rlm_ldapの場合)

+---------------------------+               +-------------+
| rlm_ldap (authorize)      | --- bind ---> | LDAP server |
|              ldap.attrmap |      query    |             |
| +--------+         |      |               | +---------+ |
| |RADIUS  | <--- mapping <-----------------| |ldap     | |
| | attr   |                |               | |  attr   | |
| +--------+                |               | +---------+ |
+---------------------------+               +-------------+

rlm_ldapモジュールのAuthorizeでは、LDAPからユーザのアトリビュート取得します。 LDAPへのbindはrlm_ldapのオプションのidentify,passwordが使われます。

LDAPから取得するアトリビュートはldap.attrmapに書かれているもので、 取得した後でRADIUSのアトリビュートに変換(マッピング)されます。

ldap.attrmapには、RADIUSのアトリビュートの種類、RADIUSのアトリビュート名、LDAPのアトリビュート名を書きます。RADIUSのアトリビュートの種類にはcheckItemreplyItemがあり、replyItemのアトリビュートは認証時にNASに送信されます。

LDAPのuserPasswordはRADIUSのUser-Passwordにマッピングされますが、 通常userPasswordの値は{crypt}....のようにcryptされた値や MD5やSHAなどでハッシュされた値が入っていますので、 rlm_mschapモジュールでのAuthenticationには使用できません。

LDAPで別のスキーマを定義してuserPassword以外のアトリビュートを 使うことも出来ますが、 その場合は、rlm_ldapのオプションのpassword_attributeに LDAPのアトリビュートの名前を指定し、 LDAPには生のパスワードを格納することになりますので、 あまりお勧めできません。

その為、rlm_mschapモジュールでAuthenticationを行う場合には、LDAPにはntPasswordlmPasswordを設定し、ハッシュされたパスワードを格納します。

(src/modules/rlm_mschap/smbencryptコマンドでハッシュされたパスワードを生成することが可能です)

Samba 3.0.xのsamba.schemaでは、スキーマが変更になり、lmPassword -> sambaLMPassword、ntPassword -> sambaNTPassword、acctFlags -> sambaAcctFlagsに変更になっています。新しいスキーマのLDAPを使う場合は、ldap.attrmapを適宜書き換える必要があります。

rlm_ldapではLDAPからユーザを取得する際に検索フィルタを指定できます。 指定したフィルタにマッチしたユーザだけを許可することが可能です。

TLSを使用する場合は、/usr/local/etc/openldap/ldap.confにTLS用の各証明書や鍵の設定を行います。

(LDAPのプロトコルバージョン2を使用する場合は、rlm_ldap.cのソースを書き換える必要があります)

access_attr_used_for_allowの値がyesの場合、 access_attrで指定したLDAPアトリビュートの値が 存在しないか、'FALSE'の時はそのユーザがロックされているとみなされます。

access_attr_used_for_allowがnoの場合、access_attrで指定したLDAPアトリビュートの値が存在する場合は、そのユーザはロックされているとみなされます。

default_profileには、デフォルトで読み込むRADIUS ProfileのDNを設定します。

profile_attributeは、ユーザ毎に違うRADIUS ProfileのDNを適用する場合に、 そのRADIUS Profileを指定するためのアトリビュートの名前を指定します。 このアトリビュートが存在する場合、この値をRADIUS profileのDNとして、指定されたprofileを読み込みます。 グループ毎にプロファイルの値を変える場合に使用します。

2-2.Authenticate (rlm_mschapの場合)

rlm_mschapモジュールのAuthenticateでは、AuthorizeモジュールによってLDAPから取得したアトリビュートを使って、認証をおこないます。

rlm_mschapモジュールのPAP/MS-CHAP/MS-CHAPv2認証では、 NT-PasswordLM-PasswordSMB-Account-Ctrl/SMB-Account-Ctrl-Textが使われます。

NT-PasswordとLM-Passwordアトリビュートが存在しない場合は、 User-Password(生パスワード)を元にNT-PasswordやLM-Passwordを計算します。

SMB-Account-Ctrl/SMB-Account-Ctrl-Textは、Windowsのユーザフラグで、 ユーザアカウントの無効やロックアウトのフラグが設定されている場合は、 認証を拒否します。 また、パスワード不要のフラグが設定されている場合は、 パスワードに関係なく許可されますが、MPPEが利用できません。

SMB-Account-Ctrl-Textは、SMB-Account-Ctrlのテキスト形式の値で、SMB-Account-Ctrlが存在しない場合に使用されます。次のような値です。

[UWDX     ]

SMB-Account-Ctrlはバイナリ形式の値で、複数のフラグのOR値です。

SMB-Account-Ctrlの値
フラグバイナリ値テキスト値説明
ACB_DISABLE0x0001Dアカウント無効
ACB_PWNOTREQ0x0004Nパスワード不要
ACB_NORMAL0x0010U有効なアカウント (設定しないと無効)
ACB_AUTOLOCK0x0400Lロックアウト

SMB-Account-Ctrl、SMB-Account-Ctrl-TEXT共に存在しない場合はACB_NORMALとみなされます。

(rlm_ldapモジュールでSAMBA LDAPのsambaAcctFlags(旧acctFlags)をSMB-Account-Ctrl-Textにマッピングする場合、 値に空白が含まれると空白の後ろが切り詰められてしまい、正しくッピングされません)

rlm_mschapモジュールでPAP認証をする場合は、LM-PasswordかNT-Passwordを使って、NASから送られてきたパスワードをLM HASH/NT HASHして比較します。

rlm_mschapモジュールでMS-CHAP/MS-CHAPv2認証する場合は、LM-PasswordとNT-Passwordを使って、NASから送られてきたChallengeからResponseを計算し、NASから送られてきたとResponseと比較します。

デフォルトではLDAPのlmPassword、ntPassword、acctFlagsのアトリビュートがマッピングされています。これらのLDAPアトリビュートはSAMBA LDAPのschemaを利用するか、独自のschemaを定義する必要があります。

2-3.Accounting (rlm_sqlの場合)

rlm_sqlモジュールのAccountingでは、NASから送られてくるAccounting-RequestをSQLサーバーに残します。

SQLサーバに残すアトリビュートは、sql.confで設定します。アクセスログを記録する場合はaccounting_start_query,accounting_start_query_alt,accounting_stop_query,accounting_stop_query_altを設定します。

accounting_onoff_query
Accounting On/Off。
accounting_update_query
Accounting update。
accounting_start_query
ユーザのアカウンティングの開始。
accounting_start_query_alt
accounting_start_queryに失敗した場合に発行されます。
accounting_stop_query
ユーザのアカウンティングの終了。
accounting_stop_query_alt
accounting_stop_queryに失敗した場合に発行されます。

VPN装置等で接続元のIPアドレス等を記録する場合は、Tunnel-Client-Endpoint等の値を追加するようにします。

3. インストール

gcc 3.3.2を使用

OpenLDAPをインストールしておく

mysqlをインストールしておく

./configure
gmake
gmake install

4. OpenLDAP 2.2.18の設定

SAMBA LDAPのスキーマとRADIUS-LDAPv3のスキーマをopenldapのschemaディレクトリに入れておきます。RADIUS-LDAPv3.schemaはfreeradius/doc/の中にあります。

slapd.conf (例)
include         /usr/local/etc/openldap/schema/core.schema
include         /usr/local/etc/openldap/schema/cosine.schema
include         /usr/local/etc/openldap/schema/inetorgperson.schema
include         /usr/local/etc/openldap/schema/nis.schema
include         /usr/local/etc/openldap/schema/solaris.schema
include         /usr/local/etc/openldap/schema/samba.schema
include         /usr/local/etc/openldap/schema/RADIUS-LDAPv3.schema

schemacheck     on

# Define global ACLs to disable default read access.

TLSCertificateFile      /usr/local/etc/openldap/server-cert.pem
TLSCertificateKeyFile   /usr/local/etc/openldap/server-key.pem
TLSCACertificateFile    /usr/local/etc/openldap/ca-cert.pem
TLSVerifyClient allow

# Do not enable referrals until AFTER you have a working directory
# service AND an understanding of referrals.
#referral       ldap://root.openldap.org

pidfile         /usr/local/var/slapd.pid
argsfile        /usr/local/var/slapd.args

# Load dynamic backend modules:
# modulepath    /usr/local/libexec/openldap
# moduleload    back_bdb.la
# moduleload    back_ldap.la
# moduleload    back_ldbm.la
# moduleload    back_passwd.la
# moduleload    back_shell.la

# Sample security restrictions
#
#   Disallow clear text exchange of passwords
# disallow bind_simple_unprotected
#
#       Require integrity protection (prevent hijacking)
#       Require 112-bit (3DES or better) encryption for updates
#       Require 63-bit encryption for simple bind
# security ssf=1 update_ssf=112 simple_bind=64

# Sample access control policy:
#       Root DSE: allow anyone to read it
#       Subschema (sub)entry DSE: allow anyone to read it
#       Other DSEs:
#               Allow self write access
#               Allow authenticated users read access
#               Allow anonymous users to authenticate
#       Directives needed to implement policy:
#access to dn.base="" by * read
#access to dn.base="cn=Subschema" by * read
#access to *
#       by self write
#       by users read
#       by anonymous auth
#
# if no access controls are present, the default policy is:
#       Allow read by all
#
# rootdn can always write!

access to dn.base="" by * read
access to dn.base="cn=Subschema" by * read
access to *
        by users read
        by anonymous auth

access to dn.sub="ou=Users,dc=waga,dc=homeip,dc=net"
        attrs=userPassword,lmPassword,ntPassword
        by self write
        by anonymous auth

#######################################################################
# ldbm database definitions
#######################################################################

database        bdb
suffix          "dc=waga,dc=homeip,dc=net"
rootdn          "cn=Manager,dc=waga,dc=homeip,dc=net"
# Cleartext passwords, especially for the rootdn, should
# be avoid.  See slappasswd(8) and slapd.conf(5) for details.
# Use of strong authentication encouraged.
rootpw          slappasswdで生成
# The database directory MUST exist prior to running slapd AND
# should only be accessible by the slapd and slap tools.
# Mode 700 recommended.
directory       /usr/local/var/openldap-data
# Indices to maintain
index   objectClass     eq
index   uid     pres,eq
index   cn,sn,dc        pres,eq,sub
index   uidNumber       pres,eq
index   gidNumber       pres,eq

5. MySQLの設定

MySQLにスキーマを作成します。src/modules/rlm_sql/drivers/rlm_sql_mysqlの中にdb_mysql.sqlファイルがあるので、これを使ってデータベースを作り、アクセスするアカウントの権限も設定します。

db_mysql.sqlに書かれているradacctテーブルのCallingStationIdとCalledStationIdは10文字になっていて、VPN等で使用する場合には、IPアドレスが入ることもある為、必要に応じて増やしておきます。その他必要なアトリビュート用のカラムも作成しておきます。

vi db_mysql.sql
  CalledStationId varchar(50) NOT NULL default '',
  CallingStationId varchar(50) NOT NULL default '',

/usr/local/mysql/bin/mysql -u root -p

mysql> create database radius;
Query OK, 1 row affected (0.02 sec)

mysql> use radius
Database changed

mysql> source db_mysql.sql
Query OK, 0 rows affected (0.03 sec)

Query OK, 0 rows affected (0.00 sec)

Query OK, 0 rows affected (0.00 sec)

Query OK, 0 rows affected (0.00 sec)

Query OK, 0 rows affected (0.01 sec)

Query OK, 0 rows affected (0.00 sec)

mysql> grant select,update,insert on radius.*
    -> to hoge@'radius.waga.homeip.net'
    -> identified by '??????????';
Query OK, 0 rows affected (0.03 sec)

mysql> alter table radacct add column TunnelClientEndpoint varchar(50);
Query OK, 0 rows affected (0.01 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> alter table radacct add column TunnelType varchar(15);
Query OK, 0 rows affected (0.01 sec)
Records: 0  Duplicates: 0  Warnings: 0

6. FreeRADIUSの設定

clients.conf クライアントのシークレットの設定(例)

client 192.168.10.10 {
        secret         = password
        shortname      = pptpserver
};

users ユーザの基本設定(例)

DEFAULT         Auth-Type := MS-CHAP,NAS-IP-Address == 192.168.10.10,Calling-Station-Id =~ ".*"

DEFAULT         Auth-Type := Reject,NAS-IP-Address == 192.168.10.10,Calling-Station-Id =~ "00.*"

DEFAULT         Auth-Type := MS-CHAP,NAS-IP-Address == 192.168.10.11

ldap.attrmapの設定

SMB-Account-CTRL-TEXTのマッピングをコメントアウトしておく。
(ldapモジュールで、acctFlagsの文字列を正しくマッピング出来ない為)

#checkItem       SMB-Account-CTRL-TEXT           acctFlags

sql.conf MySQLクライアントの設定(例)


sql {
  driver = "rlm_sql_mysql"
  server = "mysql.waga.homeip.net"
  login = "radserver"
  password = "password"
  radius_db = "radius"
  acct_table1 = "radacct"
  acct_table2 = "radacct"

  authcheck_table = "radcheck"
  authreply_table = "radreply"

  groupcheck_table = "radgroupcheck"
  groupreply_table = "radgroupreply"

  usergroup_table = "usergroup"

  deletestalesessions = yes

  sqltrace = no
  sqltracefile = ${logdir}/sqltrace.sql

  num_sql_socks = 5

  sql_user_name = "%{User-Name}"

  authorize_check_query = "SELECT id,UserName,Attribute,Value,op FROM ${authcheck_table} WHERE Username = '%{SQL-User-Name}' ORDER BY id"
  authorize_reply_query = "SELECT id,UserName,Attribute,Value,op FROM ${authreply_table} WHERE Username = '%{SQL-User-Name}' ORDER BY id"

  authorize_group_check_query = "SELECT ${groupcheck_table}.id,${groupcheck_table}.GroupName,${groupcheck_table}.Attribute,${groupcheck_table}.Value,${groupcheck_table}.op  FROM ${groupcheck_table},${usergroup_table} WHERE ${usergroup_table}.Username = '%{SQL-User-Name}' AND ${usergroup_table}.GroupName = ${groupcheck_table}.GroupName ORDER BY ${groupcheck_table}.id"
  authorize_group_reply_query = "SELECT ${groupreply_table}.id,${groupreply_table}.GroupName,${groupreply_table}.Attribute,${groupreply_table}.Value,${groupreply_table}.op  FROM ${groupreply_table},${usergroup_table} WHERE ${usergroup_table}.Username = '%{SQL-User-Name}' AND ${usergroup_table}.GroupName = ${groupreply_table}.GroupName ORDER BY ${groupreply_table}.id"

  authenticate_query = "SELECT Value,Attribute FROM ${authcheck_table} WHERE UserName = '%{User-Name}' AND ( Attribute = 'User-Password' OR Attribute = 'Password' OR Attribute = 'Crypt-Password' ) ORDER BY Attribute DESC"

  accounting_onoff_query = "UPDATE ${acct_table1} SET AcctStopTime='%S', AcctSessionTime=unix_timestamp('%S') - unix_timestamp(AcctStartTime), AcctTerminateCause='%{Acct-Terminate-Cause}', AcctStopDelay = %{Acct-Delay-Time} WHERE AcctSessionTime=0 AND AcctStopTime=0 AND NASIPAddress= '%{NAS-IP-Address}' AND AcctStartTime <= '%S'"

   accounting_update_query = "UPDATE ${acct_table1} SET FramedIPAddress = '%{Framed-IP-Address}' WHERE AcctSessionId = '%{Acct-Session-Id}' AND UserName = '%{SQL-User-Name}' AND NASIPAddress= '%{NAS-IP-Address}'"

   accounting_start_query = "INSERT into radacct (RadAcctId, AcctSessionId, AcctUniqueId, UserName, Realm, NASIPAddress, NASPortId, NASPortType, AcctStartTime, AcctStopTime, AcctSessionTime, AcctAuthentic, ConnectInfo_start, ConnectInfo_stop, AcctInputOctets, AcctOutputOctets, CalledStationId, CallingStationId, AcctTerminateCause, ServiceType, FramedProtocol, FramedIPAddress, AcctStartDelay, AcctStopDelay, TunnelClientEndpoint) values('', '%{Acct-Session-Id}', '%{Acct-Unique-Session-Id}', '%{SQL-User-Name}', '%{Realm}', '%{NAS-IP-Address}', '%{NAS-Port-Id}', '%{NAS-Port-Type}', '%S', '0', '0', '%{Acct-Authentic}', '%{Connect-Info}', '', '0', '0', '%{Called-Station-Id}', '%{Calling-Station-Id}', '', '%{Service-Type}', '%{Framed-Protocol}', '%{Framed-IP-Address}', '%{Acct-Delay-Time}', '0', '%{Tunnel-Client-Endpoint}')"

   accounting_start_query_alt  = "UPDATE ${acct_table1} SET AcctStartTime = '%S', AcctStartDelay = '%{Acct-Delay-Time}', ConnectInfo_start = '%{Connect-Info}' WHERE AcctSessionId = '%{Acct-Session-Id}' AND UserName = '%{SQL-User-Name}' AND NASIPAddress = '%{NAS-IP-Address}'"

   accounting_stop_query = "UPDATE ${acct_table1} SET AcctStopTime = '%S', AcctSessionTime = '%{Acct-Session-Time}', AcctInputOctets = '%{Acct-Input-Octets}', AcctOutputOctets = '%{Acct-Output-Octets}', AcctTerminateCause = '%{Acct-Terminate-Cause}', AcctStopDelay = '%{Acct-Delay-Time}', ConnectInfo_stop = '%{Connect-Info}' WHERE AcctSessionId = '%{Acct-Session-Id}' AND UserName = '%{SQL-User-Name}' AND NASIPAddress = '%{NAS-IP-Address}'"

   accounting_stop_query_alt = "INSERT into radacct (RadAcctId, AcctSessionId, AcctUniqueId, UserName, Realm, NASIPAddress, NASPortId, NASPortType, AcctStartTime, AcctStopTime, AcctSessionTime, AcctAuthentic, ConnectInfo_start, ConnectInfo_stop, AcctInputOctets, AcctOutputOctets, CalledStationId, CallingStationId, AcctTerminateCause, ServiceType, FramedProtocol, FramedIPAddress, AcctStartDelay, AcctStopDelay, TunnelClientEndpoint) values('', '%{Acct-Session-Id}', '%{Acct-Unique-Session-Id}', '%{SQL-User-Name}', '%{Realm}', '%{NAS-IP-Address}', '%{NAS-Port-Id}', '%{NAS-Port-Type}', '0', '%S', '%{Acct-Session-Time}', '%{Acct-Authentic}', '', '%{Connect-Info}', '%{Acct-Input-Octets}', '%{Acct-Output-Octets}', '%{Called-Station-Id}', '%{Calling-Station-Id}', '%{Acct-Terminate-Cause}', '%{Service-Type}', '%{Framed-Protocol}', '%{Framed-IP-Address}', '0', '%{Acct-Delay-Time}', '%{Tunnel-Client-Endpoint}')"

}

radiusd.conf radiusサーバーの設定(例)


prefix = /usr/local
exec_prefix = ${prefix}
sysconfdir = ${prefix}/etc
localstatedir = ${prefix}/var
sbindir = ${exec_prefix}/sbin
logdir = ${localstatedir}/log/radius
raddbdir = ${sysconfdir}/raddb
radacctdir = ${logdir}/radacct

confdir = ${raddbdir}
run_dir = ${localstatedir}/run

libdir = ${exec_prefix}/lib

pidfile = ${run_dir}/radiusd.pid

user = root
group = root

max_request_time = 30

delete_blocked_requests = no

cleanup_delay = 5

max_requests = 1024

bind_address = *

port = 1645

checkrad = ${sbindir}/checkrad

hostname_lookups = no

allow_core_dumps = no

regular_expressions     = yes
extended_expressions    = yes

log_stripped_names = no

log_auth = no

log_auth_badpass = no
log_auth_goodpass = no

usercollide = no

lower_user = no
lower_pass = no

nospace_user = no
nospace_pass = no

security {
        max_attributes = 200
        reject_delay = 1
}

proxy_requests  = no
$INCLUDE  ${confdir}/proxy.conf

$INCLUDE  ${confdir}/clients.conf

$INCLUDE  ${confdir}/snmp.conf

thread pool {
        start_servers = 5
        max_servers = 32
        min_spare_servers = 3
        max_spare_servers = 10
        max_requests_per_server = 0
}

modules {
        mschap {
                authtype = MS-CHAP
                use_mppe = yes
                require_encryption = yes
                require_strong = yes
        }

        ldap {
                server = "localhost"
                identity = "cn=admin,dc=waga,dc=homeip,dc=net"
                password = "password"
                basedn = "ou=People,dc=waga,dc=homeip,dc=net"
                filter = "(uid=%u)"
                start_tls = no
                default_profile = "cn=SambaRadProfile,dc=waga,dc=homeip,dc=net"
                profile_attribute = "radiusProfileDn"
                dictionary_mapping = ${raddbdir}/ldap.attrmap
                ldap_connections_number = 5
                timeout = 4
                timelimit = 3
                net_timeout = 1
        }

        preprocess {
                huntgroups = ${confdir}/huntgroups
                hints = ${confdir}/hints
                with_ascend_hack = no
                ascend_channels_per_line = 23
                with_ntdomain_hack = no
                with_specialix_jetstream_hack = no
                with_cisco_vsa_hack = no
        }

        files {
                usersfile = ${confdir}/users
                acctusersfile = ${confdir}/acct_users
                compat = no
        }

        detail {
                detailfile = ${radacctdir}/%{Client-IP-Address}/detail
                detailperm = 0600
        }

        $INCLUDE  ${confdir}/sql.conf

        radutmp {
                filename = ${logdir}/radutmp
                perm = 0600
                callerid = "yes"
        }

        attr_filter {
                attrsfile = ${confdir}/attrs
        }
}

authorize {
        preprocess
        ldap
        files
}

authenticate {
        mschap
}

preacct {
        suffix
        files
        preprocess
}

accounting {
        detail
        sql
}

session {
        radutmp
}