<?php /* copyright */ /* ========================================================================== */ /* freeradius.inc part of pfSense (http://www.pfSense.com) Copyright (C) 2013 Alexander Wilke <nachtfalkeaw@web.de> Copyright (C) 2013 Marcello Coutinho All rights reserved. Based on m0n0wall (http://m0n0.ch/wall) Copyright (C) 2003-2006 Manuel Kasper <mk@neon1.net>. All rights reserved. */ /* ========================================================================== */ /* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* ========================================================================== */ require_once('config.inc'); require_once('service-utils.inc'); require_once("util.inc"); require_once("functions.inc"); require_once("pkg-utils.inc"); require_once("globals.inc"); require_once("filter.inc"); require_once("services.inc"); // Check pfSense version $pfs_version = substr(trim(file_get_contents("/etc/version")),0,3); if ($pfs_version > 2.0){ define('FREERADIUS_BASE', '/usr/pbi/freeradius-' . php_uname("m")); } else{ define('FREERADIUS_BASE', '/usr/local'); } // Check freeradius lib version $frlib=""; $libfiles = scandir(FREERADIUS_BASE . "/lib/"); foreach ($libfiles as $libfile){ if (preg_match("/freeradius-/",$libfile)) $frlib=FREERADIUS_BASE . "/lib/{$libfile}"; } if ($frlib == ""){ log_error("freeRADIUS - No freeradius lib found on ".FREERADIUS_BASE."/lib"); } function freeradius_deinstall_command() { if (substr(trim(file_get_contents("/etc/version")),0,3) == "2.0") { exec("cd /var/db/pkg && pkg_delete `ls | grep freeradius`"); exec("rm -rf " . FREERADIUS_BASE . "/etc/raddb"); exec("rm -rf /var/run/radiusd/"); } } function freeradius_install_command() { global $config; conf_mount_rw(); // put the constant to a variable $varFREERADIUS_BASE = FREERADIUS_BASE; // We create here different folders for different counters. if (!file_exists("/var/log/radacct/datacounter/")) { exec("mkdir /var/log/radacct/datacounter && mkdir /var/log/radacct/datacounter/daily && mkdir /var/log/radacct/datacounter/weekly && mkdir /var/log/radacct/datacounter/monthly && mkdir /var/log/radacct/datacounter/forever"); } if (!file_exists("/var/log/radacct/timecounter/")) { exec("mkdir /var/log/radacct/timecounter"); } exec("mkdir " . FREERADIUS_BASE . "/etc/raddb/scripts"); if (!file_exists("/var/log/radutmp")) { exec("touch /var/log/radutmp"); } if (!file_exists("/var/log/radwtmp")) { exec("touch /var/log/radwtmp"); } exec("chown -R root:wheel " . FREERADIUS_BASE . "/etc/raddb && chown -R root:wheel {$frlib} && chown -R root:wheel /var/log/radacct"); // creating a backup file of the original policy.conf no matter if user checked this or not if (!file_exists(FREERADIUS_BASE . "/etc/raddb/policy.conf.backup")) { log_error("FreeRADIUS: Creating backup of the original file to " . FREERADIUS_BASE . "/etc/raddb/policy.conf.backup"); copy(FREERADIUS_BASE . "/etc/raddb/policy.conf", FREERADIUS_BASE . "/etc/raddb/policy.conf.backup"); } // creating a backup file of the original /modules/files no matter if user checked this or not if (!file_exists(FREERADIUS_BASE . "/etc/raddb/files.backup")) { log_error("FreeRADIUS: Creating backup of the original file to " . FREERADIUS_BASE . "/etc/raddb/files.backup"); copy(FREERADIUS_BASE . "/etc/raddb/modules/files", FREERADIUS_BASE . "/etc/raddb/files.backup"); } // Disable virtual-server we do not need by default if (file_exists(FREERADIUS_BASE . "/etc/raddb/sites-enabled/control-socket")) { unlink(FREERADIUS_BASE . "/etc/raddb/sites-enabled/control-socket"); } if (file_exists(FREERADIUS_BASE . "/etc/raddb/sites-enabled/inner-tunnel")) { unlink(FREERADIUS_BASE . "/etc/raddb/sites-enabled/inner-tunnel"); } // We run this here just to suppress some warnings on syslog if file doesn't exist freeradius_authorizedmacs_resync(); // These two functions create the module and the dictionary entry for Mobile-One-Time-Password freeradius_dictionary_resync(); freeradius_modulesmotp_resync(); // Here we create the modules and scripts for the datacounter freeradius_modulesdatacounter_resync(); freeradius_datacounter_acct_resync(); freeradius_datacounter_auth_resync(); // Some initial module configuration freeradius_modulesmschap_resync(); freeradius_modulesrealm_resync(); freeradius_modulescounter_resync(); // Initialize some config files - the functions below call other functions freeradius_sqlconf_resync(); freeradius_eapconf_resync(); freeradius_clients_resync(); $rcfile = array(); $rcfile['file'] = 'radiusd.sh'; $rcfile['start'] = "$varFREERADIUS_BASE" . '/etc/rc.d/radiusd onestart'; $rcfile['stop'] = "$varFREERADIUS_BASE" . '/etc/rc.d/radiusd onestop'; write_rcfile($rcfile); conf_mount_ro(); start_service("radiusd"); } function freeradius_settings_resync() { global $config; $conf = ''; // put the constant to a variable $varFREERADIUS_BASE = FREERADIUS_BASE; // We do some checks of some folders which will be deleted after reboot on nanobsd systems if (!file_exists("/var/log/radacct/")) { exec("mkdir /var/log/radacct"); } if (!file_exists("/var/log/radacct/datacounter/")) { exec("mkdir /var/log/radacct/datacounter && mkdir /var/log/radacct/datacounter/daily && mkdir /var/log/radacct/datacounter/weekly && mkdir /var/log/radacct/datacounter/monthly && mkdir /var/log/radacct/datacounter/forever"); } if (!file_exists("/var/log/radacct/timecounter/")) { exec("mkdir /var/log/radacct/timecounter"); } if (!file_exists("/var/log/radutmp")) { exec("touch /var/log/radutmp"); } if (!file_exists("/var/log/radwtmp")) { exec("touch /var/log/radwtmp"); } if (!file_exists("/var/log/radacct/")) { exec("chown -R root:wheel /var/log/radacct"); } $varsettings = $config['installedpackages']['freeradiussettings']['config'][0]; // Variables: General configuration $varsettingsmaxrequests = ($varsettings['varsettingsmaxrequests']?$varsettings['varsettingsmaxrequests']:'1024'); $varsettingsmaxrequesttime = ($varsettings['varsettingsmaxrequesttime']?$varsettings['varsettingsmaxrequesttime']:'30'); $varsettingscleanupdelay = ($varsettings['varsettingscleanupdelay']?$varsettings['varsettingscleanupdelay']:'5'); $varsettingshostnamelookups = ($varsettings['varsettingshostnamelookups']?$varsettings['varsettingshostnamelookups']:'no'); $varsettingsallowcoredumps = ($varsettings['varsettingsallowcoredumps']?$varsettings['varsettingsallowcoredumps']:'no'); $varsettingsregularexpressions = ($varsettings['varsettingsregularexpressions']?$varsettings['varsettingsregularexpressions']:'yes'); $varsettingsextendedexpressions = ($varsettings['varsettingsextendedexpressions']?$varsettings['varsettingsextendedexpressions']:'yes'); // Variables: Logging options $varsettingslogdir = ($varsettings['varsettingslogdir']?$varsettings['varsettingslogdir']:'syslog'); $varsettingsauth = ($varsettings['varsettingsauth']?$varsettings['varsettingsauth']:'yes'); $varsettingsauthbadpass = ($varsettings['varsettingsauthbadpass']?$varsettings['varsettingsauthbadpass']:'no'); $varsettingsauthbadpassmessage = ($varsettings['varsettingsauthbadpassmessage']?$varsettings['varsettingsauthbadpassmessage']:''); $varsettingsauthgoodpass = ($varsettings['varsettingsauthgoodpass']?$varsettings['varsettingsauthgoodpass']:'no'); $varsettingsauthgoodpassmessage = ($varsettings['varsettingsauthgoodpassmessage']?$varsettings['varsettingsauthgoodpassmessage']:''); $varsettingsstrippednames = ($varsettings['varsettingsstrippednames']?$varsettings['varsettingsstrippednames']:'no'); // Variables: Security $varsettingsmaxattributes = ($varsettings['varsettingsmaxattributes']?$varsettings['varsettingsmaxattributes']:'200'); $varsettingsrejectdelay = ($varsettings['varsettingsrejectdelay']?$varsettings['varsettingsrejectdelay']:'1'); // Variables: Thread Pool $varsettingsstartservers = ($varsettings['varsettingsstartservers']?$varsettings['varsettingsstartservers']:'5'); $varsettingsmaxservers = ($varsettings['varsettingsmaxservers']?$varsettings['varsettingsmaxservers']:'32'); $varsettingsminspareservers = ($varsettings['varsettingsminspareservers']?$varsettings['varsettingsminspareservers']:'3'); $varsettingsmaxspareservers = ($varsettings['varsettingsmaxspareservers']?$varsettings['varsettingsmaxspareservers']:'10'); $varsettingsmaxqueuesize = ($varsettings['varsettingsmaxqueuesize']?$varsettings['varsettingsmaxqueuesize']:'65536'); $varsettingsmaxrequestsperserver = ($varsettings['varsettingsmaxrequestsperserver']?$varsettings['varsettingsmaxrequestsperserver']:'0'); // For more details look at "freeradius_sqlconf_resync" $sqlconf = $config['installedpackages']['freeradiussqlconf']['config'][0]; // Dis-/Enable SQL in "instatiate" section in "freeradius_settings_resync" and radiusd.conf SQL SERVER 2 if ($sqlconf['varsqlconf2includeenable'] == 'on') { $varsqlconf2instantiate = 'sql2'; } else { $varsqlconf2instantiate = '### sql2 DISABLED ###'; } $varsqlconf2failover = ($varsettings['varsqlconf2failover']?$varsettings['varsqlconf2failover']:'redundant'); // Dis-/Enable SQL in "instatiate" section in "freeradius_settings_resync" and radiusd.conf SQL SERVER 1 if ($sqlconf['varsqlconfincludeenable'] == 'on') { $varsqlconfinclude = '$INCLUDE sql.conf'; $varsqlconfincludecounter = '$INCLUDE sql/mysql/counter.conf'; $varsqlconfinstantiate = "$varsqlconf2failover {" . "\n\t\tsql" . "\n\t\t$varsqlconf2instantiate" . "\n\t}"; } else { $varsqlconfinclude = '#$INCLUDE sql.conf'; $varsqlconfincludecounter = '#$INCLUDE sql/mysql/counter.conf'; $varsqlconf2failover = ''; $varsqlconfinstantiate = '#sql'; } $conf .= <<<EOD prefix = $varFREERADIUS_BASE exec_prefix = \${prefix} sysconfdir = \${prefix}/etc localstatedir = /var sbindir = \${exec_prefix}/sbin logdir = \${localstatedir}/log raddbdir = \${sysconfdir}/raddb radacctdir = \${logdir}/radacct confdir = \${raddbdir} run_dir = \${localstatedir}/run libdir = {$frlib} pidfile = \${run_dir}/radiusd.pid db_dir = \${raddbdir} name = radiusd #chroot = /path/to/chroot/directory #user = freeradius #group = freeradius ############################################################################### ### Is not present in freeradius 2.x radiusd.conf anymore but it was in 1.x ### ### delete_blocked_requests = no ### ### usercollide = no ### ### lower_user = no ### ### lower_pass = no ### ### nospace_user = no ### ### nospace_pass = no ### ############################################################################### max_request_time = $varsettingsmaxrequesttime cleanup_delay = $varsettingscleanupdelay max_requests = $varsettingsmaxrequests hostname_lookups = $varsettingshostnamelookups allow_core_dumps = $varsettingsallowcoredumps regular_expressions = $varsettingsregularexpressions extended_expressions = $varsettingsextendedexpressions EOD; // Deletes virtual-server coa by default. Will be re-enabled if there is an interface-type "coa" exec("rm -f " . FREERADIUS_BASE . "/etc/raddb/sites-enabled/coa"); $arrinterfaces = $config['installedpackages']['freeradiusinterfaces']['config']; if (is_array($arrinterfaces) && !empty($arrinterfaces)) { foreach ($arrinterfaces as $item) { $varinterfaceip = $item['varinterfaceip']; $varinterfaceport = $item['varinterfaceport']; $varinterfacetype = $item['varinterfacetype']; $varinterfaceipversion = $item['varinterfaceipversion']; // Begin "if" for interface-type = detail if ($item['varinterfacetype'] == 'detail') { $conf .= <<<EOD listen { type = $varinterfacetype $varinterfaceipversion = $varinterfaceip port = $varinterfaceport filename = \${radacctdir}/detail-%Y%m%d:%H load_factor = 10 } EOD; } // End "if" for interface-type = detail // Begin "if" for interface-type = coa if ($item['varinterfacetype'] == 'coa') { // Enables virtual-server coa because interface-type is coa exec("ln -s " . FREERADIUS_BASE . "/etc/raddb/sites-available/coa " . FREERADIUS_BASE . "/etc/raddb/sites-enabled/"); $conf .= <<<EOD listen { type = $varinterfacetype $varinterfaceipversion = $varinterfaceip port = $varinterfaceport server = coa } EOD; } // End "if" for interface-type = coa // Begin "if" for interface-type = auth, acct, proxy, status if (($item['varinterfacetype'] == 'auth') || ($item['varinterfacetype'] == 'acct') || ($item['varinterfacetype'] == 'proxy') || ($item['varinterfacetype'] == 'status')) { $conf .= <<<EOD listen { type = $varinterfacetype $varinterfaceipversion = $varinterfaceip port = $varinterfaceport } EOD; } // End "if" for interface-type = auth, acct, proxy, status } // end foreach } // end if array $conf .= <<<EOD log { destination = $varsettingslogdir file = \${logdir}/radius.log syslog_facility = daemon stripped_names = $varsettingsstrippednames auth = $varsettingsauth auth_badpass = $varsettingsauthbadpass auth_goodpass = $varsettingsauthgoodpass msg_goodpass = "$varsettingsauthgoodpassmessage" msg_badpass = "$varsettingsauthbadpassmessage" } checkrad = \${sbindir}/checkrad security { max_attributes = $varsettingsmaxattributes reject_delay = $varsettingsrejectdelay status_server = no } ### disbale proxy module. In most environments we do not need to proxy requests to another RADIUS PROXY server #proxy_requests = yes #\$INCLUDE proxy.conf \$INCLUDE clients.conf thread pool { start_servers = $varsettingsstartservers max_servers = $varsettingsmaxservers min_spare_servers = $varsettingsminspareservers max_spare_servers = $varsettingsmaxspareservers max_queue_size = $varsettingsmaxqueuesize max_requests_per_server = $varsettingsmaxrequestsperserver } modules { \$INCLUDE \${confdir}/modules/ \$INCLUDE eap.conf ### Dis-/Enable sql.conf INCLUDE $varsqlconfinclude ### Dis-/Enable sql/mysql/counter.conf INCLUDE $varsqlconfincludecounter #\$INCLUDE sqlippool.conf } instantiate { exec expr daily weekly monthly forever expiration logintime ### Dis-/Enable sql instatiate $varsqlconfinstantiate } \$INCLUDE policy.conf \$INCLUDE sites-enabled/ EOD; conf_mount_rw(); file_put_contents(FREERADIUS_BASE . '/etc/raddb/radiusd.conf', $conf); conf_mount_ro(); // "freeradius_sqlconf_resync" is pointing to this function because we need to run "freeradius_serverdefault_resync" and after that restart freeradius. freeradius_plainmacauth_resync(); freeradius_motp_resync(); freeradius_serverdefault_resync(); // This is to fix the mysqlclient.so which gets lost after reboot exec("ldconfig -m /usr/local/lib/mysql"); // Change owner of freeradius created files exec("chown -R root:wheel /var/log"); restart_service("radiusd"); } function freeradius_users_resync() { global $config; $conf = ''; $arrusers = $config['installedpackages']['freeradius']['config']; if (is_array($arrusers) && !empty($arrusers)) { foreach ($arrusers as $users) { // Variables for users file defined parameters $varusersusername = $users['varusersusername']; $varuserspassword = $users['varuserspassword']; // Check password encryption $varuserspasswordencryption = ($users['varuserspasswordencryption']?$users['varuserspasswordencryption']:'Cleartext-Password'); switch ($varuserspasswordencryption) { case "MD5-Password": $varuserspassword = md5($varuserspassword); break; default: $varuserspassword = $users['varuserspassword']; } $varusersmotpinitsecret = $users['varusersmotpinitsecret']; $varusersmotppin = $users['varusersmotppin']; $varusersmotpoffset = ($users['varusersmotpoffset']?$users['varusersmotpoffset']:'0'); $varuserssimultaneousconnect = ($users['varuserssimultaneousconnect']?$users['varuserssimultaneousconnect']:''); $varuserswisprredirectionurl = $users['varuserswisprredirectionurl']; $varusersframedipaddress = $users['varusersframedipaddress']; $varusersframedipnetmask = $users['varusersframedipnetmask']; $varusersframedroute = $users['varusersframedroute']; $varusersexpiration = $users['varusersexpiration']; $varuserssessiontimeout = $users['varuserssessiontimeout']; $varuserslogintime = $users['varuserslogintime']; $varusersvlanid = $users['varusersvlanid']; // GUI uses minutes but RADIUS needs seconds so we do a multiplication $varusersamountoftime = ($users['varusersamountoftime']?$users['varusersamountoftime']:''); $varusersamountoftime = $varusersamountoftime * 60; $varuserspointoftime = $users['varuserspointoftime']; // GUI uses MB but RADIUS needs Bytes so we do a multiplication $varusersmaxtotaloctets = ($users['varusersmaxtotaloctets']?$users['varusersmaxtotaloctets']:''); $varusersmaxtotaloctets = $varusersmaxtotaloctets * 1024 * 1024; $varusersmaxtotaloctetstimerange = $users['varusersmaxtotaloctetstimerange']; // GUI uses KiloBit but RADIUS needs Bits so we do a multiplication $varusersmaxbandwidthup = ($users['varusersmaxbandwidthup']?$users['varusersmaxbandwidthup']:''); $varusersmaxbandwidthup = $varusersmaxbandwidthup * 1024; $varusersmaxbandwidthdown = ($users['varusersmaxbandwidthdown']?$users['varusersmaxbandwidthdown']:''); $varusersmaxbandwidthdown = $varusersmaxbandwidthdown * 1024; // Accounting-Interim-Interval - Must not be smaller than 60 and should be bigger than 600s if (($users['varusersacctinteriminterval'] >= '0') && ($users['varusersacctinteriminterval'] < '60')) { $varusersacctinteriminterval = 60; } else { $varusersacctinteriminterval = $users['varusersacctinteriminterval']; } // Clear variables for next user foreach additional options TOP $varuserstopadditionaloptions = ''; $varusersadditionaloptionstop = ''; if(!empty($users['varuserstopadditionaloptions'])) { $varuserstopadditionaloptions = explode("|", ($users['varuserstopadditionaloptions'])); foreach ($varuserstopadditionaloptions as $toptmp) { $varusersadditionaloptionstop .= $toptmp . "\n"; } } // Clear variables for next user foreach additional options: CHECK-ITEMS $varuserscheckitemsadditionaloptions = ''; $varusersadditionaloptionscheckitems = ''; if(!empty($users['varuserscheckitemsadditionaloptions'])) { $varuserscheckitemsadditionaloptions = explode("|", ($users['varuserscheckitemsadditionaloptions'])); $varusersadditionaloptionscheckitems .= ''; foreach ($varuserscheckitemsadditionaloptions as $checkitemtmp) { $varusersadditionaloptionscheckitems .= "$checkitemtmp" . " "; } } // Clear variables for next user foreach additional options: REPLY-ITEMS $varusersreplyitemsadditionaloptions = ''; $varusersadditionaloptionsreplyitems = ''; if(!empty($users['varusersreplyitemsadditionaloptions'])) { $varusersreplyitemsadditionaloptions = explode("|", ($users['varusersreplyitemsadditionaloptions'])); $varusersadditionaloptionsreplyitems .= ''; foreach ($varusersreplyitemsadditionaloptions as $replyitemtmp) { $varusersadditionaloptionsreplyitems .= $replyitemtmp . "\n\t"; } } // Empty variable $varuserscheckitem = ''; $varusersreplyitem = ''; // check if mobile otp is disabled if ($users['varusersmotpenable'] == '') { // If someone does not want to use username/password but entry "DEFAULT" instead then we can disable this if (($users['varusersusername'] == '') && ($users['varuserspassword'] == '')) { $varuserscheckitem = ''; } else { // Add the user attributes to each user. $varuserscheckitem = '"' . $varusersusername . '"' . " $varuserspasswordencryption := " . '"' . $varuserspassword .'"'; } } // end of check if otp is enabled // if otp is enabled we need to set Auth-Type to accept because password will be checked when the otp script gets executed in reply-item list else { $varuserscheckitem = '"' . $varusersusername . '"' . " Auth-Type = motp"; } // Add additional CHECK-ITEMS here. Different formatting in "users" file needed. if ($varuserssimultaneousconnect != '') { $varuserscheckitem .= ", Simultaneous-Use := " . '"' . $varuserssimultaneousconnect . '"'; } if ($varusersexpiration != '') { $varuserscheckitem .= ", Expiration := " . '"' . $varusersexpiration . '"'; } if ($varuserslogintime != '') { $varuserscheckitem .= ", Login-Time := " . '"' . $varuserslogintime . '"'; } if ($varusersamountoftime != '') { $varuserscheckitem .= ", Max-" . "$varuserspointoftime" . "-Session := " . "$varusersamountoftime"; } if ($varusersadditionaloptionscheckitems != '') { $varuserscheckitem .= ", $varusersadditionaloptionscheckitems"; } // this is the part for mobile otp if ($users['varusersmotpenable'] == 'on') { $varusersreplyitem .= "MOTP-Init-Secret = $varusersmotpinitsecret," . "\n\tMOTP-PIN = $varusersmotppin," . "\n\tMOTP-Offset = $varusersmotpoffset"; } else { $varusersreplyitem .= ''; } // Add additional REPLY-ITEMS here. Different formatting in "users" file needed. if ($varusersframedipaddress != '') { if ($varusersreplyitem != '') { $varusersreplyitem .=","; } $varusersreplyitem .= "\n\tFramed-IP-Address = $varusersframedipaddress"; } if ($varusersframedipnetmask != '') { if ($varusersreplyitem != '') { $varusersreplyitem .=","; } $varusersreplyitem .= "\n\tFramed-IP-Netmask = $varusersframedipnetmask"; } if ($varusersframedroute != '') { if ($varusersreplyitem != '') { $varusersreplyitem .=","; } $varusersreplyitem .= "\n\tFramed-Route = " . '"' . $varusersframedroute . '"'; } if ($varuserssessiontimeout != '') { if ($varusersreplyitem != '') { $varusersreplyitem .=","; } $varusersreplyitem .= "\n\tSession-Timeout := $varuserssessiontimeout"; } if ($varusersvlanid != '') { if ($varusersreplyitem != '') { $varusersreplyitem .=","; } $varusersreplyitem .= "\n\tTunnel-Type = VLAN,\n\tTunnel-Medium-Type = IEEE-802,\n\tTunnel-Private-Group-ID = " . '"' . $varusersvlanid . '"'; } if ($varusersmaxbandwidthup != '') { if ($varusersreplyitem != '') { $varusersreplyitem .=","; } $varusersreplyitem .= "\n\tWISPr-Bandwidth-Max-Up := $varusersmaxbandwidthup"; } if ($varusersmaxbandwidthdown != '') { if ($varusersreplyitem != '') { $varusersreplyitem .=","; } $varusersreplyitem .= "\n\tWISPr-Bandwidth-Max-Down := $varusersmaxbandwidthdown"; } if ($varusersacctinteriminterval != '') { if ($varusersreplyitem != '') { $varusersreplyitem .=","; } $varusersreplyitem .= "\n\tAcct-Interim-Interval := $varusersacctinteriminterval"; } if ($varuserswisprredirectionurl != '') { if ($varusersreplyitem != '') { $varusersreplyitem .=","; } $varusersreplyitem .= "\n\tWISPr-Redirection-URL := $varuserswisprredirectionurl"; } // If an octet limit is set we create the files for the limit and the counter. Further we call an exec script which checks if the limit is reached or not if ($varusersmaxtotaloctets != '') { if ($varusersreplyitem != '') { $varusersreplyitem .=","; } //create exec script $varusersreplyitem .= "\n\tExec-Program-Wait = " . '"/bin/sh ' . FREERADIUS_BASE . '/etc/raddb/scripts/datacounter_auth.sh ' . "$varusersusername $varusersmaxtotaloctetstimerange" . '"'; // create limit file - will be always overwritten so we can increase limit from GUI exec("`echo $varusersmaxtotaloctets > /var/log/radacct/datacounter/$varusersmaxtotaloctetstimerange/max-octets-$varusersusername`"); // if used-octets file exist we do NOT overwrite this file!!! if (!file_exists("/var/log/radacct/datacounter/$varusersmaxtotaloctetstimerange/used-octets-$varusersusername")) { exec("echo 0 > /var/log/radacct/datacounter/$varusersmaxtotaloctetstimerange/used-octets-$varusersusername"); } } // If an octet limit is NOT set we delete the files for the limit and the counter. else { if (file_exists("/var/log/radacct/datacounter/$varusersmaxtotaloctetstimerange/max-octets-$varusersusername")) { unlink("/var/log/radacct/datacounter/$varusersmaxtotaloctetstimerange/max-octets-$varusersusername"); } if (file_exists("/var/log/radacct/datacounter/$varusersmaxtotaloctetstimerange/used-octets-$varusersusername")) { unlink("/var/log/radacct/datacounter/$varusersmaxtotaloctetstimerange/used-octets-$varusersusername"); } } if ($varusersadditionaloptionsreplyitems != '') { if ($varusersreplyitem != '') { $varusersreplyitem .=","; } $varusersreplyitem .= "\n\t$varusersadditionaloptionsreplyitems"; } // Cosmetic fix - This is just to make a blank new line after each user entry $varusersreplyitem .= "\n\n"; $conf .= <<<EOD $varusersadditionaloptionstop $varuserscheckitem $varusersreplyitem EOD; } //end foreach } // end if $filename = FREERADIUS_BASE . '/etc/raddb/users'; conf_mount_rw(); file_put_contents($filename, $conf); chmod($filename, 0640); conf_mount_ro(); freeradius_sync_on_changes(); restart_service('radiusd'); } function freeradius_authorizedmacs_resync() { global $config; $conf = ''; $arrmacs = $config['installedpackages']['freeradiusauthorizedmacs']['config']; if (is_array($arrmacs) && !empty($arrmacs)) { foreach ($arrmacs as $macs) { // Variables for authorized_macs file defined parameters $varmacsaddress = $macs['varmacsaddress']; // We don't need a password but we need this field to make syntac correct for CHECK-ITEMS $varmacspassword = $macs['varmacsaddress']; $varmacssimultaneousconnect = ($macs['varmacssimultaneousconnect']?$macs['varmacssimultaneousconnect']:''); $varmacsswisprredirectionurl = $macs['varmacsswisprredirectionurl']; $varmacsframedipaddress = $macs['varmacsframedipaddress']; $varmacsframedipnetmask = $macs['varmacsframedipnetmask']; $varmacsframedroute = $macs['varmacsframedroute']; $varmacsexpiration = $macs['varmacsexpiration']; $varmacssessiontimeout = $macs['varmacssessiontimeout']; $varmacslogintime = $macs['varmacslogintime']; $varmacsvlanid = $macs['varmacsvlanid']; // GUI uses minutes but RADIUS needs seconds so we do a multiplication $varmacsamountoftime = ($macs['varmacsamountoftime']?$macs['varmacsamountoftime']:''); $varmacsamountoftime = $varmacsamountoftime * 60; $varmacspointoftime = $macs['varmacspointoftime']; // GUI uses MB but RADIUS needs Bytes so we do a multiplication $varmacsmaxtotaloctets = ($macs['varmacsmaxtotaloctets']?$macs['varmacsmaxtotaloctets']:''); $varmacsmaxtotaloctets = $varmacsmaxtotaloctets * 1024 * 1024; $varmacsmaxtotaloctetstimerange = $macs['varmacsmaxtotaloctetstimerange']; // GUI uses KiloBit but RADIUS needs Bits so we do a multiplication $varmacsmaxbandwidthup = ($macs['varmacsmaxbandwidthup']?$macs['varmacsmaxbandwidthup']:''); $varmacsmaxbandwidthup = $varmacsmaxbandwidthup * 1024; $varmacsmaxbandwidthdown = ($macs['varmacsmaxbandwidthdown']?$macs['varmacsmaxbandwidthdown']:''); $varmacsmaxbandwidthdown = $varmacsmaxbandwidthdown * 1024; // Accounting-Interim-Interval if (($users['varmacsacctinteriminterval'] >= '0') && ($users['varmacsacctinteriminterval'] < '60')) { $varmacsacctinteriminterval = 60; } else { $varmacsacctinteriminterval = $users['varmacsacctinteriminterval']; } // Clear variables for next mac foreach additional options TOP $varmacstopadditionaloptions = ''; $varmacsadditionaloptionstop = ''; if(!empty($macs['varmacstopadditionaloptions'])) { $varmacstopadditionaloptions = explode("|", ($macs['varmacstopadditionaloptions'])); foreach ($varmacstopadditionaloptions as $toptmp) { $varmacsadditionaloptionstop .= $toptmp . "\n"; } } // Clear variables for next mac foreach additional options: CHECK-ITEMS $varmacscheckitemsadditionaloptions = ''; $varmacsadditionaloptionscheckitems = ''; if(!empty($macs['varmacscheckitemsadditionaloptions'])) { $varmacscheckitemsadditionaloptions = explode("|", ($macs['varmacscheckitemsadditionaloptions'])); $varmacsadditionaloptionscheckitems .= ''; foreach ($varmacscheckitemsadditionaloptions as $checkitemtmp) { $varmacsadditionaloptionscheckitems .= "$checkitemtmp" . " "; } } // Clear variables for next mac foreach additional options: REPLY-ITEMS $varmacsreplyitemsadditionaloptions = ''; $varmacsadditionaloptionsreplyitems = ''; if(!empty($macs['varmacsreplyitemsadditionaloptions'])) { $varmacsreplyitemsadditionaloptions = explode("|", ($macs['varmacsreplyitemsadditionaloptions'])); $varmacsadditionaloptionsreplyitems .= ''; foreach ($varmacsreplyitemsadditionaloptions as $replyitemtmp) { $varmacsadditionaloptionsreplyitems .= $replyitemtmp . "\n\t"; } } // Empty variable $varmacscheckitem = ''; $varmacsreplyitem = ''; // If someone does not want to use MAC address but entry "DEFAULT" instead then we can disable this if ($macs['varmacsaddress'] == '') { $varmacscheckitem = ''; } else { // Add the user attributes to each user. $varmacscheckitem = "$varmacsaddress" . " Cleartext-Password := " . '"' . $varmacspassword . '"'; } // Add additional CHECK-ITEMS here. Different formatting in "authorized_macs" file needed. if ($varmacssimultaneousconnect != '') { $varmacscheckitem .= ", Simultaneous-Use := " . '"' . $varmacssimultaneousconnect . '"'; } if ($varmacsexpiration != '') { $varmacscheckitem .= ", Expiration := " . '"' . $varmacsexpiration . '"'; } if ($varmacslogintime != '') { $varmacscheckitem .= ", Login-Time := " . '"' . $varmacslogintime . '"'; } if ($varmacsamountoftime != '') { $varmacscheckitem .= ", Max-" . "$varmacspointoftime" . "-Session := " . "$varmacsamountoftime"; } if ($varmacsadditionaloptionscheckitems != '') { $varmacscheckitem .= ", $varmacsadditionaloptionscheckitems"; } // Add additional REPLY-ITEMS here. Different formatting in "authorized_macs" file needed. if ($varmacsframedipaddress != '') { if ($varmacsreplyitem != '') { $varmacsreplyitem .=","; } $varmacsreplyitem .= "\n\tFramed-IP-Address = $varmacsframedipaddress"; } if ($varmacsframedipnetmask != '') { if ($varmacsreplyitem != '') { $varmacsreplyitem .=","; } $varmacsreplyitem .= "\n\tFramed-IP-Netmask = $varmacsframedipnetmask"; } if ($varmacsframedroute != '') { if ($varmacsreplyitem != '') { $varmacsreplyitem .=","; } $varmacsreplyitem .= "\n\tFramed-Route = " . '"' . $varmacsframedroute . '"'; } if ($varmacssessiontimeout != '') { if ($varmacsreplyitem != '') { $varmacsreplyitem .=","; } $varmacsreplyitem .= "\n\tSession-Timeout := $varmacssessiontimeout"; } if ($varmacsvlanid != '') { if ($varmacsreplyitem != '') { $varmacsreplyitem .=","; } $varmacsreplyitem .= "\n\tTunnel-Type = VLAN,\n\tTunnel-Medium-Type = IEEE-802,\n\tTunnel-Private-Group-ID = " . '"' . $varmacsvlanid . '"'; } if ($varmacsmaxbandwidthup != '') { if ($varmacsreplyitem != '') { $varmacsreplyitem .=","; } $varmacsreplyitem .= "\n\tWISPr-Bandwidth-Max-Up := $varmacsmaxbandwidthup"; } if ($varmacsmaxbandwidthdown != '') { if ($varmacsreplyitem != '') { $varmacsreplyitem .=","; } $varmacsreplyitem .= "\n\tWISPr-Bandwidth-Max-Down := $varmacsmaxbandwidthdown"; } if ($varmacsacctinteriminterval != '') { if ($varmacsreplyitem != '') { $varmacsreplyitem .=","; } $varmacsreplyitem .= "\n\tAcct-Interim-Interval := $varmacsacctinteriminterval"; } if ($varmacswisprredirectionurl != '') { if ($varmacsreplyitem != '') { $varmacsreplyitem .=","; } $varmacsreplyitem .= "\n\tWISPr-Redirection-URL := $varmacsswisprredirectionurl"; } // If an octet limit is set we create the files for the limit and the counter. Further we call an exec script which checks if the limit is reached or not if ($varmacsmaxtotaloctets != '') { if ($varmacsreplyitem != '') { $varmacsreplyitem .=","; } //create exec script $varmacsreplyitem .= "\n\tExec-Program-Wait = " . '"/bin/sh ' . FREERADIUS_BASE . '/etc/raddb/scripts/datacounter_auth.sh ' . "$varmacsaddress $varmacsmaxtotaloctetstimerange" . '"'; // create limit file - will be always overwritten so we can increase limit from GUI exec("`echo $varmacsmaxtotaloctets > /var/log/radacct/datacounter/$varmacsmaxtotaloctetstimerange/max-octets-$varmacsaddress`"); // if used-octets file exist we do NOT overwrite this file!!! if (!file_exists("/var/log/radacct/datacounter/$varmacsmaxtotaloctetstimerange/used-octets-$varmacsaddress")) { exec("echo 0 > /var/log/radacct/datacounter/$varmacsmaxtotaloctetstimerange/used-octets-$varmacsaddress"); } } // If an octet limit is NOT set we delete the files for the limit and the counter. else { if (file_exists("/var/log/radacct/datacounter/$varmacsmaxtotaloctetstimerange/max-octets-$varmacsaddress")) { unlink("/var/log/radacct/datacounter/$varmacsmaxtotaloctetstimerange/max-octets-$varmacsaddress"); } if (file_exists("/var/log/radacct/datacounter/$varmacsmaxtotaloctetstimerange/used-octets-$varmacsaddress")) { unlink("/var/log/radacct/datacounter/$varmacsmaxtotaloctetstimerange/used-octets-$varmacsaddress"); } } if ($varmacsadditionaloptionsreplyitems != '') { if ($varmacsreplyitem != '') { $varmacsreplyitem .=","; } $varmacsreplyitem .= "\n\t$varmacsadditionaloptionsreplyitems"; } // Cosmetic fix - This is just to make a blank new line after each macs entry $varmacsreplyitem .= "\n\n"; $conf .= <<<EOD $varmacsadditionaloptionstop $varmacscheckitem $varmacsreplyitem EOD; } //end foreach } // end if $filename = FREERADIUS_BASE . '/etc/raddb/authorized_macs'; conf_mount_rw(); file_put_contents($filename, $conf); chmod($filename, 0640); conf_mount_ro(); freeradius_sync_on_changes(); restart_service('radiusd'); } function freeradius_clients_resync() { global $config; $conf = ''; $arrclients = $config['installedpackages']['freeradiusclients']['config']; if (is_array($arrclients) && !empty($arrclients)) { foreach ($arrclients as $item) { $varclientip = $item['varclientip']; $varclientsharedsecret = $item['varclientsharedsecret']; $varclientipversion = $item['varclientipversion']; $varclientshortname = $item['varclientshortname']; $varclientproto = $item['varclientproto']; $varrequiremessageauthenticator = $item['varrequiremessageauthenticator']; $varclientnastype = $item['varclientnastype']; $varclientmaxconnections = $item['varclientmaxconnections']; $varclientlogininput = ($item['varclientlogininput']?$item['varclientlogininput']:'### login = !root ###'); $varclientpasswordinput = ($item['varclientpasswordinput']?$item['varclientpasswordinput']:'### password = someadminpass ###'); if ($item['varclientlogininput'] == '') { $varclientlogin = '### login = !root ###'; } else { $varclientlogin = "login = $varclientlogininput"; } if ($item['varclientpasswordinput'] == '') { $varclientpassword = '### password = someadminpass ###'; } else { $varclientpassword = "password = $varclientpasswordinput"; } $conf .= <<<EOD client "$varclientshortname" { $varclientipversion = $varclientip proto = $varclientproto secret = $varclientsharedsecret require_message_authenticator = $varrequiremessageauthenticator max_connections = $varclientmaxconnections shortname = $varclientshortname nastype = $varclientnastype $varclientlogin $varclientpassword } EOD; } } else { $conf .= <<<EOD client pfsense { ipaddr = 127.0.0.1 secret = pfsense shortname = pfsense } EOD; } conf_mount_rw(); file_put_contents(FREERADIUS_BASE . '/etc/raddb/clients.conf', $conf); conf_mount_ro(); freeradius_sync_on_changes(); restart_service("radiusd"); } function freeradius_eapconf_resync() { global $config; // We make this write enabled here because embedded systems need to write certs in ../raddb/certs/ folder conf_mount_rw(); $conf = ''; $eapconf = $config['installedpackages']['freeradiuseapconf']['config'][0]; // Disable weak EAP types like MD5, GTC, LEAP if ($eapconf['vareapconfdisableweakeaptypes'] == '') { $vareapconfweakeaptypes = "md5 {" . "\n\t\t}" . "\n\t\tleap {" . "\n\t\t}" . "\n\t\tgtc {" . "\n\t\t\t#challenge = " . '"Password: "' . "\n\t\t\tauth_type = PAP" . "\n\t\t}"; } else { $vareapconfweakeaptypes = '### DISABLED WEAK EAP TYPES MD5, GTC, LEAP ###'; } // Variables: EAP $vareapconfdefaulteaptype = ($eapconf['vareapconfdefaulteaptype']?$eapconf['vareapconfdefaulteaptype']:'md5'); $vareapconftimerexpire = ($eapconf['vareapconftimerexpire']?$eapconf['vareapconftimerexpire']:'60'); $vareapconfignoreunknowneaptypes = ($eapconf['vareapconfignoreunknowneaptypes']?$eapconf['vareapconfignoreunknowneaptypes']:'no'); $vareapconfciscoaccountingusernamebug = ($eapconf['vareapconfciscoaccountingusernamebug']?$eapconf['vareapconfciscoaccountingusernamebug']:'no'); $vareapconfmaxsessions = ($eapconf['vareapconfmaxsessions']?$eapconf['vareapconfmaxsessions']:'4096'); // Variables: EAP-TLS $vareapconfprivatekeypassword = ($eapconf['vareapconfprivatekeypassword']?$eapconf['vareapconfprivatekeypassword']:'whatever'); $vareapconffragmentsize = ($eapconf['vareapconffragmentsize']?$eapconf['vareapconffragmentsize']:'1024'); $vareapconfincludelength = ($eapconf['vareapconfincludelength']?$eapconf['vareapconfincludelength']:'yes'); $vareapconfcountry = ($eapconf['vareapconfcountry']?$eapconf['vareapconfcountry']:'US'); $vareapconfstate = ($eapconf['vareapconfstate']?$eapconf['vareapconfstate']:'Texas'); $vareapconfcity = ($eapconf['vareapconfcity']?$eapconf['vareapconfcity']:'Austin'); $vareapconforganization = ($eapconf['vareapconforganization']?$eapconf['vareapconforganization']:'My Company Ltd'); $vareapconfemail = ($eapconf['vareapconfemail']?$eapconf['vareapconfemail']:'admin@mycompany.com'); $vareapconfcommonname = ($eapconf['vareapconfcommonname']?$eapconf['vareapconfcommonname']:'internal-ca'); // Variables: Cache $vareapconfcacheenablecache = ($eapconf['vareapconfcacheenablecache']?$eapconf['vareapconfcacheenablecache']:'no'); $vareapconfcachelifetime = ($eapconf['vareapconfcachelifetime']?$eapconf['vareapconfcachelifetime']:'24'); $vareapconfcachemaxentries = ($eapconf['vareapconfcachemaxentries']?$eapconf['vareapconfcachemaxentries']:'255'); // Variables OSCP $vareapconfocspenable = ($eapconf['vareapconfocspenable']?$eapconf['vareapconfocspenable']:'no'); $vareapconfocspoverridecerturl = ($eapconf['vareapconfocspoverridecerturl']?$eapconf['vareapconfocspoverridecerturl']:'no'); $vareapconfocspurl = ($eapconf['vareapconfocspurl']?$eapconf['vareapconfocspurl']:'http://127.0.0.1/ocsp/'); // Variables: EAP-TTLS $vareapconfttlsdefaulteaptype = ($eapconf['vareapconfttlsdefaulteaptype']?$eapconf['vareapconfttlsdefaulteaptype']:'md5'); $vareapconfttlscopyrequesttotunnel = ($eapconf['vareapconfttlscopyrequesttotunnel']?$eapconf['vareapconfttlscopyrequesttotunnel']:'no'); $vareapconfttlsusetunneledreply = ($eapconf['vareapconfttlsusetunneledreply']?$eapconf['vareapconfttlsusetunneledreply']:'no'); $vareapconfttlsincludelength = ($eapconf['vareapconfttlsincludelength']?$eapconf['vareapconfttlsincludelength']:'yes'); // Variables: EAP-PEAP with MSCHAPv2 $vareapconfpeapdefaulteaptype = ($eapconf['vareapconfpeapdefaulteaptype']?$eapconf['vareapconfpeapdefaulteaptype']:'mschapv2'); $vareapconfpeapcopyrequesttotunnel = ($eapconf['vareapconfpeapcopyrequesttotunnel']?$eapconf['vareapconfpeapcopyrequesttotunnel']:'no'); $vareapconfpeapusetunneledreply = ($eapconf['vareapconfpeapusetunneledreply']?$eapconf['vareapconfpeapusetunneledreply']:'no'); $vareapconfpeapsohenable = ($eapconf['vareapconfpeapsohenable']?$eapconf['vareapconfpeapsohenable']:'Disable'); // This is for enable/disbable MS SoH in EAP-PEAP and the virtuial-server "soh-server" if ($eapconf['vareapconfpeapsohenable'] == 'Enable') { $vareapconfpeapsoh = 'soh = yes' . "\n\t\t\tsoh_virtual_server = " . '"' . "soh-server" . '"'; exec("ln -s " . FREERADIUS_BASE . "/etc/raddb/sites-available/soh " . FREERADIUS_BASE . "/etc/raddb/sites-enabled/"); } else { $vareapconfpeapsoh = '### MS SoH Server is disabled ###'; if (file_exists(FREERADIUS_BASE . "/etc/raddb/sites-enabled/soh")) { exec("rm -f " . FREERADIUS_BASE . "/etc/raddb/sites-enabled/soh"); } } // The filenames of pfsense cert manager are different from freeradius cert manager so it is possible to store both in the same folder at any time. // This is for the pfsense cert manager // Depends on "freeradius_get_server_certs" and "freeradius_get_ca_certs" if ($eapconf['vareapconfchoosecertmanager'] == 'on') { $ca_cert = lookup_ca($eapconf["ssl_ca_cert"]); if ($ca_cert != false) { if(base64_decode($ca_cert['prv'])) { file_put_contents(FREERADIUS_BASE . "/etc/raddb/certs/ca_key.pem", base64_decode($ca_cert['prv'])); $conf['ssl_ca_key'] = FREERADIUS_BASE . '/etc/raddb/certs/ca_key.pem'; } if(base64_decode($ca_cert['crt'])) { $crl_cert = lookup_crl($eapconf["ssl_ca_crl"]); if ($crl_cert != false){ $crl=base64_decode($crl_cert['text']); $check_crl="check_crl = yes"; } else{ $check_crl="check_crl = no"; } file_put_contents(FREERADIUS_BASE . "/etc/raddb/certs/ca_cert.pem", base64_decode($ca_cert['crt']). $crl); $conf['ssl_ca_cert'] = FREERADIUS_BASE . "/etc/raddb/certs/ca_cert.pem"; } $svr_cert = lookup_cert($eapconf["ssl_server_cert"]); if ($svr_cert != false) { if(base64_decode($svr_cert['prv'])) { file_put_contents(FREERADIUS_BASE . "/etc/raddb/certs/server_key.pem", base64_decode($svr_cert['prv'])); $conf['ssl_key'] = FREERADIUS_BASE . '/etc/raddb/certs/server_key.pem'; } } if(base64_decode($svr_cert['crt'])) { file_put_contents(FREERADIUS_BASE . "/etc/raddb/certs/server_cert.pem", base64_decode($svr_cert['crt'])); $conf['ssl_server_cert'] = FREERADIUS_BASE . "/etc/raddb/certs/server_cert.pem"; } /* Not needed anymore because pfsense can do this by default if ($eapconf['vareapconfenableclientp12'] == 'on') { $svr_cert = lookup_cert($eapconf["ssl_client_cert"]); if ($svr_cert != false) { if(base64_decode($svr_cert['prv'])) { file_put_contents(FREERADIUS_BASE . "/etc/raddb/certs/client_key.pem", base64_decode($svr_cert['prv'])); $conf['ssl_key'] = FREERADIUS_BASE . '/etc/raddb/certs/client_key.pem'; } } if(base64_decode($svr_cert['crt'])) { file_put_contents(FREERADIUS_BASE . "/etc/raddb/certs/client_cert.pem", base64_decode($svr_cert['crt'])); $conf['ssl_client_cert'] = FREERADIUS_BASE . "/etc/raddb/certs/client_cert.pem"; } exec("openssl pkcs12 -export -in " . FREERADIUS_BASE . "/etc/raddb/certs/client_cert.pem -inkey " . FREERADIUS_BASE . "/etc/raddb/certs/client_key.pem -out " . FREERADIUS_BASE . "/etc/raddb/certs/client_cert.p12 -passout pass\:"); } */ $conf['ssl_cert_dir'] = FREERADIUS_BASE . '/etc/raddb/certs'; } $vareapconfprivatekeyfile = 'server_key.pem'; $vareapconfcertificatefile = 'server_cert.pem'; $vareapconfcafile = 'ca_cert.pem'; // generate new DH and RANDOM file // We create a single empty file just to check if there is really a change from one to another cert manager to avoid building ne DH and random files if (!file_exists(FREERADIUS_BASE . "/etc/raddb/certs/pfsense_cert_mgr")) { log_error("freeRADIUS: Switched to pfSense Cert-Manager. Creating new DH and random file in " . FREERADIUS_BASE . "/etc/raddb/certs"); exec("cd " . FREERADIUS_BASE . "/etc/raddb/certs && openssl dhparam -out dh 1024"); exec("cd " . FREERADIUS_BASE . "/etc/raddb/certs && dd if=/dev/urandom of=./random count=10"); exec("touch " . FREERADIUS_BASE . "/etc/raddb/certs/pfsense_cert_mgr"); } } // This is for freeradius cert manager else { $vareapconfprivatekeyfile = 'server.pem'; $vareapconfcertificatefile = 'server.pem'; $vareapconfcafile = 'ca.pem'; } // check if the common name of the certificate must match the username if($eapconf['vareapconfenablecheckcertcn'] == 'on') { $vareapconfcheckcertcn = 'check_cert_cn = %{User-Name}'; } else { $vareapconfcheckcertcn = '### check_cert_cn = %{User-Name} ###'; } // check if cert issuer of CA and certs match if($eapconf['vareapconfenablecheckcertissuer'] == 'on') { $vareapconfcheckcertissuer = "check_cert_issuer = " . '"' . "/C=$vareapconfcountry/ST=$vareapconfstate/L=$vareapconfcity/O=$vareapconforganization/emailAddress=$vareapconfemail/CN=$vareapconfcommonname" . '"'; } else { $vareapconfcheckcertissuer = '### check_cert_issuer = "/C=GB/ST=Berkshire/L=Newbury/O=My Company Ltd/emailAddress=test@mycomp.com/CN=myca" ###'; } $conf .= <<<EOD ### EAP eap { default_eap_type = $vareapconfdefaulteaptype timer_expire = $vareapconftimerexpire ignore_unknown_eap_types = $vareapconfignoreunknowneaptypes cisco_accounting_username_bug = $vareapconfciscoaccountingusernamebug max_sessions = $vareapconfmaxsessions $vareapconfweakeaptypes ### EAP-TLS and EAP-TLS with OCSP support tls { certdir = \${confdir}/certs cadir = \${confdir}/certs private_key_password = $vareapconfprivatekeypassword private_key_file = \${certdir}/$vareapconfprivatekeyfile certificate_file = \${certdir}/$vareapconfcertificatefile CA_file = \${cadir}/$vareapconfcafile dh_file = \${certdir}/dh random_file = \${certdir}/random fragment_size = $vareapconffragmentsize include_length = $vareapconfincludelength {$check_crl} CA_path = \${cadir} $vareapconfcheckcertissuer $vareapconfcheckcertcn cipher_list = "DEFAULT" ecdh_curve = "prime256v1" cache { enable = $vareapconfcacheenablecache lifetime = $vareapconfcachelifetime max_entries = $vareapconfcachemaxentries } verify { # tmpdir = /tmp/radiusd # client = "/path/to/openssl verify -CApath ${CA_path} %{TLS-Client-Cert-Filename}" } ocsp { enable = $vareapconfocspenable override_cert_url = $vareapconfocspoverridecerturl url = "$vareapconfocspurl" } } ### EAP-TTLS ttls { default_eap_type = $vareapconfttlsdefaulteaptype copy_request_to_tunnel = $vareapconfttlscopyrequesttotunnel use_tunneled_reply = $vareapconfttlsusetunneledreply include_length = $vareapconfttlsincludelength } ### end ttls ### EAP-PEAP peap { default_eap_type = $vareapconfpeapdefaulteaptype copy_request_to_tunnel = $vareapconfpeapcopyrequesttotunnel use_tunneled_reply = $vareapconfpeapusetunneledreply # proxy_tunneled_request_as_eap = yes $vareapconfpeapsoh } mschapv2 { # send_error = no } } EOD; $filename = FREERADIUS_BASE . '/etc/raddb/eap.conf'; file_put_contents($filename, $conf); chmod($filename, 0640); conf_mount_ro(); restart_service('radiusd'); } // Gets started from freeradiuseapconf.xml function freeradius_get_ca_certs() { global $config; $ca_arr = array(); $ca_arr[] = array('refid' => 'none', 'descr' => 'none'); foreach ($config['ca'] as $ca) { $ca_arr[] = array('refid' => $ca['refid'], 'descr' => $ca['descr']); } return $ca_arr; } // Gets started from freeradiuseapconf.xml function freeradius_get_ca_crl() { global $config; $crl_arr = array(); $crl_arr[] = array('refid' => 'none', 'descr' => 'none'); foreach ($config['crl'] as $crl) { $crl_arr[] = array('refid' => $crl['refid'], 'descr' => $crl['descr']); } return $crl_arr; } // Gets started from freeradiuseapconf.xml function freeradius_get_server_certs() { global $config; $cert_arr = array(); $cert_arr[] = array('refid' => 'none', 'descr' => 'none'); foreach ($config['cert'] as $cert) { $cert_arr[] = array('refid' => $cert['refid'], 'descr' => $cert['descr']); } return $cert_arr; } function freeradius_sqlconf_resync() { global $config; $conf = ''; $sqlconf = $config['installedpackages']['freeradiussqlconf']['config'][0]; // Variables: SQL DATABASE 1 $varsqlconfdatabase = ($sqlconf['varsqlconfdatabase']?$sqlconf['varsqlconfdatabase']:'mysql'); $varsqlconfserver = ($sqlconf['varsqlconfserver']?$sqlconf['varsqlconfserver']:'localhost'); $varsqlconfport = ($sqlconf['varsqlconfport']?$sqlconf['varsqlconfport']:'3306'); $varsqlconflogin = ($sqlconf['varsqlconflogin']?$sqlconf['varsqlconflogin']:'radius'); $varsqlconfpassword = ($sqlconf['varsqlconfpassword']?$sqlconf['varsqlconfpassword']:'radpass'); $varsqlconfradiusdb = ($sqlconf['varsqlconfradiusdb']?$sqlconf['varsqlconfradiusdb']:'radius'); $varsqlconfaccttable1 = ($sqlconf['varsqlconfaccttable1']?$sqlconf['varsqlconfaccttable1']:'radacct'); $varsqlconfaccttable2 = ($sqlconf['varsqlconfaccttable2']?$sqlconf['varsqlconfaccttable2']:'radacct'); $varsqlconfpostauthtable = ($sqlconf['varsqlconfpostauthtable']?$sqlconf['varsqlconfpostauthtable']:'radpostauth'); $varsqlconfauthchecktable = ($sqlconf['varsqlconfauthchecktable']?$sqlconf['varsqlconfauthchecktable']:'radcheck'); $varsqlconfauthreplytable = ($sqlconf['varsqlconfauthreplytable']?$sqlconf['varsqlconfauthreplytable']:'radreply'); $varsqlconfgroupchecktable = ($sqlconf['varsqlconfgroupchecktable']?$sqlconf['varsqlconfgroupchecktable']:'radgroupcheck'); $varsqlconfgroupreplytable = ($sqlconf['varsqlconfgroupreplytable']?$sqlconf['varsqlconfgroupreplytable']:'radgroupreply'); $varsqlconfusergrouptable = ($sqlconf['varsqlconfusergrouptable']?$sqlconf['varsqlconfusergrouptable']:'radusergroup'); $varsqlconfreadgroups = ($sqlconf['varsqlconfreadgroups']?$sqlconf['varsqlconfreadgroups']:'yes'); $varsqlconfdeletestalesessions = ($sqlconf['varsqlconfdeletestalesessions']?$sqlconf['varsqlconfdeletestalesessions']:'yes'); $varsqlconfsqltrace = ($sqlconf['varsqlconfsqltrace']?$sqlconf['varsqlconfsqltrace']:'no'); $varsqlconfnumsqlsocks = ($sqlconf['varsqlconfnumsqlsocks']?$sqlconf['varsqlconfnumsqlsocks']:'5'); $varsqlconfconnectfailureretrydelay = ($sqlconf['varsqlconfconnectfailureretrydelay']?$sqlconf['varsqlconfconnectfailureretrydelay']:'60'); $varsqlconflifetime = ($sqlconf['varsqlconflifetime']?$sqlconf['varsqlconflifetime']:'0'); $varsqlconfmaxqueries = ($sqlconf['varsqlconfmaxqueries']?$sqlconf['varsqlconfmaxqueries']:'0'); $varsqlconfreadclients = ($sqlconf['varsqlconfreadclients']?$sqlconf['varsqlconfreadclients']:'yes'); $varsqlconfnastable = ($sqlconf['varsqlconfnastable']?$sqlconf['varsqlconfnastable']:'nas'); // Additional changes were made in "freeradius_settings_resync" // Variables: SQL DATABASE 2 $varsqlconf2database = ($sqlconf['varsqlconf2database']?$sqlconf['varsqlconf2database']:'mysql'); $varsqlconf2server = ($sqlconf['varsqlconf2server']?$sqlconf['varsqlconf2server']:'localhost'); $varsqlconf2port = ($sqlconf['varsqlconf2port']?$sqlconf['varsqlconf2port']:'3306'); $varsqlconf2login = ($sqlconf['varsqlconf2login']?$sqlconf['varsqlconf2login']:'radius'); $varsqlconf2password = ($sqlconf['varsqlconf2password']?$sqlconf['varsqlconf2password']:'radpass'); $varsqlconf2radiusdb = ($sqlconf['varsqlconf2radiusdb']?$sqlconf['varsqlconf2radiusdb']:'radius'); $varsqlconf2accttable1 = ($sqlconf['varsqlconf2accttable1']?$sqlconf['varsqlconf2accttable1']:'radacct'); $varsqlconf2accttable2 = ($sqlconf['varsqlconf2accttable2']?$sqlconf['varsqlconf2accttable2']:'radacct'); $varsqlconf2postauthtable = ($sqlconf['varsqlconf2postauthtable']?$sqlconf['varsqlconf2postauthtable']:'radpostauth'); $varsqlconf2authchecktable = ($sqlconf['varsqlconf2authchecktable']?$sqlconf['varsqlconf2authchecktable']:'radcheck'); $varsqlconf2authreplytable = ($sqlconf['varsqlconf2authreplytable']?$sqlconf['varsqlconf2authreplytable']:'radreply'); $varsqlconf2groupchecktable = ($sqlconf['varsqlconf2groupchecktable']?$sqlconf['varsqlconf2groupchecktable']:'radgroupcheck'); $varsqlconf2groupreplytable = ($sqlconf['varsqlconf2groupreplytable']?$sqlconf['varsqlconf2groupreplytable']:'radgroupreply'); $varsqlconf2usergrouptable = ($sqlconf['varsqlconf2usergrouptable']?$sqlconf['varsqlconf2usergrouptable']:'radusergroup'); $varsqlconf2readgroups = ($sqlconf['varsqlconf2readgroups']?$sqlconf['varsqlconf2readgroups']:'yes'); $varsqlconf2deletestalesessions = ($sqlconf['varsqlconf2deletestalesessions']?$sqlconf['varsqlconf2deletestalesessions']:'yes'); $varsqlconf2sqltrace = ($sqlconf['varsqlconf2sqltrace']?$sqlconf['varsqlconf2sqltrace']:'no'); $varsqlconf2numsqlsocks = ($sqlconf['varsqlconf2numsqlsocks']?$sqlconf['varsqlconf2numsqlsocks']:'5'); $varsqlconf2connectfailureretrydelay = ($sqlconf['varsqlconf2connectfailureretrydelay']?$sqlconf['varsqlconf2connectfailureretrydelay']:'60'); $varsqlconf2lifetime = ($sqlconf['varsqlconf2lifetime']?$sqlconf['varsqlconf2lifetime']:'0'); $varsqlconf2maxqueries = ($sqlconf['varsqlconf2maxqueries']?$sqlconf['varsqlconf2maxqueries']:'0'); $varsqlconf2readclients = ($sqlconf['varsqlconf2readclients']?$sqlconf['varsqlconf2readclients']:'yes'); $varsqlconf2nastable = ($sqlconf['varsqlconf2nastable']?$sqlconf['varsqlconf2nastable']:'nas'); // Additional changes were made in "freeradius_settings_resync" $conf .= <<<EOD sql { database = "$varsqlconfdatabase" driver = "rlm_sql_\${database}" server = "$varsqlconfserver" port = $varsqlconfport login = "$varsqlconflogin" password = "$varsqlconfpassword" radius_db = "$varsqlconfradiusdb" acct_table1 = "$varsqlconfaccttable1" acct_table2 = "$varsqlconfaccttable2" postauth_table = "$varsqlconfpostauthtable" authcheck_table = "$varsqlconfauthchecktable" authreply_table = "$varsqlconfauthreplytable" groupcheck_table = "$varsqlconfgroupchecktable" groupreply_table = "$varsqlconfgroupreplytable" usergroup_table = "$varsqlconfusergrouptable" read_groups = $varsqlconfreadgroups deletestalesessions = $varsqlconfdeletestalesessions sqltrace = $varsqlconfsqltrace sqltracefile = \${logdir}/sqltrace.sql num_sql_socks = $varsqlconfnumsqlsocks connect_failure_retry_delay = $varsqlconfconnectfailureretrydelay lifetime = $varsqlconflifetime max_queries = $varsqlconfmaxqueries readclients = $varsqlconfreadclients nas_table = "$varsqlconfnastable" \$INCLUDE sql/\${database}/dialup.conf } sql sql2 { database = "$varsqlconf2database" driver = "rlm_sql_\${database}" server = "$varsqlconf2server" port = $varsqlconf2port login = "$varsqlconf2login" password = "$varsqlconf2password" radius_db = "$varsqlconf2radiusdb" acct_table1 = "$varsqlconf2accttable1" acct_table2 = "$varsqlconf2accttable2" postauth_table = "$varsqlconf2postauthtable" authcheck_table = "$varsqlconf2authchecktable" authreply_table = "$varsqlconf2authreplytable" groupcheck_table = "$varsqlconf2groupchecktable" groupreply_table = "$varsqlconf2groupreplytable" usergroup_table = "$varsqlconf2usergrouptable" read_groups = $varsqlconf2readgroups deletestalesessions = $varsqlconf2deletestalesessions sqltrace = $varsqlconf2sqltrace sqltracefile = \${logdir}/sqltrace.sql num_sql_socks = $varsqlconf2numsqlsocks connect_failure_retry_delay = $varsqlconf2connectfailureretrydelay lifetime = $varsqlconf2lifetime max_queries = $varsqlconf2maxqueries readclients = $varsqlconf2readclients nas_table = "$varsqlconf2nastable" \$INCLUDE sql/\${database}/dialup.conf } EOD; $filename = FREERADIUS_BASE . '/etc/raddb/sql.conf'; conf_mount_rw(); file_put_contents($filename, $conf); chmod($filename, 0640); conf_mount_ro(); // We don't need a restart at this time because there are additional changes needed in: // "freeradius_settings_resync" and "freeradius_serverdefault_resync". // restart_service('radiusd'); freeradius_settings_resync(); } function freeradius_serverdefault_resync() { global $config; $conf = ''; // Get Variables from freeradiusmodulesldap.xml $arrmodulesldap = $config['installedpackages']['freeradiusmodulesldap']['config'][0]; // failover/loadbalancing mode $varmodulesldap2failover = ($arrmodulesldap['varmodulesldap2failover']?$arrmodulesldap['varmodulesldap2failover']:'redundant'); // If unchecked then disable authorize ldap2 if (!$arrmodulesldap['varmodulesldap2enableauthorize']) { $varmodulesldap2enableauthorize = '### ldap2 disabled ###'; } else { $varmodulesldap2enableauthorize = 'ldap2'; } // If unchecked then disable authorize ldap1 if (!$arrmodulesldap['varmodulesldapenableauthorize']) { $varmodulesldapenableauthorize = '### ldap ###'; } else { $varmodulesldapenableauthorize = ''; $varmodulesldapenableauthorize .= "$varmodulesldap2failover {"; $varmodulesldapenableauthorize .= "\n\t\tldap"; // this line adds ldap2 when activated $varmodulesldapenableauthorize .= "\n\t\t$varmodulesldap2enableauthorize"; $varmodulesldapenableauthorize .= "\n\t}"; } // If unchecked then disable authenticate for ldap1 if (!$arrmodulesldap['varmodulesldap2enableauthenticate']) { $varmodulesldap2enableauthenticate = "### ldap2 disabled ###"; } else { $varmodulesldap2enableauthenticate = "ldap2"; } // If unchecked then disable authenticate ldap2 if (!$arrmodulesldap['varmodulesldapenableauthenticate']) { $varmodulesldapenableauthenticate = "#Auth-Type LDAP {" . "\n\t\t\t#ldap" . "\n\t\t\t$varmodulesldap2enableauthenticate" . "\n\t#}"; } else { $varmodulesldapenableauthenticate = "Auth-Type LDAP {" . "\n\t\t\tldap" . "\n\t\t\t$varmodulesldap2enableauthenticate" . "\n\t}"; } // Get Variables from freeradiussqlconf.xml for DATABASE 1 $sqlconf = $config['installedpackages']['freeradiussqlconf']['config'][0]; $varsqlconfenableauthorize = ($sqlconf['varsqlconfenableauthorize']?$sqlconf['varsqlconfenableauthorize']:'Disable'); $varsqlconfenableaccounting = ($sqlconf['varsqlconfenableaccounting']?$sqlconf['varsqlconfenableaccounting']:'Disable'); $varsqlconfenablesession = ($sqlconf['varsqlconfenablesession']?$sqlconf['varsqlconfenablesession']:'Disable'); $varsqlconfenablepostauth = ($sqlconf['varsqlconfenablepostauth']?$sqlconf['varsqlconfenablepostauth']:'Disable'); // Get Variables from freeradiussqlconf.xml for DATABASE 2 $varsqlconf2enableauthorize = ($sqlconf['varsqlconf2enableauthorize']?$sqlconf['varsqlconf2enableauthorize']:'Disable'); $varsqlconf2enableaccounting = ($sqlconf['varsqlconf2enableaccounting']?$sqlconf['varsqlconf2enableaccounting']:'Disable'); $varsqlconf2enablesession = ($sqlconf['varsqlconf2enablesession']?$sqlconf['varsqlconf2enablesession']:'Disable'); $varsqlconf2enablepostauth = ($sqlconf['varsqlconf2enablepostauth']?$sqlconf['varsqlconf2enablepostauth']:'Disable'); // authorize section DATABASE 2 if ($sqlconf['varsqlconf2enableauthorize'] == 'Enable') { $varsqlconf2authorize = 'sql2'; } else { $varsqlconf2authorize = '### sql2 DISABLED ###'; } // accounting section DATABASE 2 if ($sqlconf['varsqlconf2enableaccounting'] == 'Enable') { $varsqlconf2accounting = 'sql2'; } else { $varsqlconf2accounting = '### sql2 DISABLED ###'; } // session section DATABASE 2 if ($sqlconf['varsqlconf2enablesession'] == 'Enable') { $varsqlconf2session = 'sql2'; } else { $varsqlconf2session = '### sql2 DISABLED ###'; } // post-auth section DATABASE 2 if ($sqlconf['varsqlconf2enablepostauth'] == 'Enable') { $varsqlconf2postauth = 'sql2'; } else { $varsqlconf2postauth = '### sql2 DISABLED ###'; } // Failover mode $varsqlconf2failover = ($sqlconf['varsqlconf2failover']?$sqlconf['varsqlconf2failover']:'redundant'); // authorize section DATABASE 1 if (($sqlconf['varsqlconfincludeenable'] == 'on') && ($sqlconf['varsqlconfenableauthorize'] == 'Enable')) { $varsqlconfauthorize = "$varsqlconf2failover {" . "\n\t\t\tsql" . "\n\t\t\t$varsqlconf2authorize" . "\n\t}"; } else { $varsqlconfauthorize = '### sql DISABLED ###'; } // accounting section DATABASE 1 if (($sqlconf['varsqlconfincludeenable'] == 'on') && ($sqlconf['varsqlconfenableaccounting'] == 'Enable')) { $varsqlconfaccounting = "$varsqlconf2failover {" . "\n\t\t\tsql" . "\n\t\t\t$varsqlconf2accounting" . "\n\t}"; } else { $varsqlconfaccounting = '### sql DISABLED ###'; } // session section DATABASE 1 if (($sqlconf['varsqlconfincludeenable'] == 'on') && ($sqlconf['varsqlconfenablesession'] == 'Enable')) { $varsqlconfsession = "$varsqlconf2failover {" . "\n\t\t\tsql" . "\n\t\t\t$varsqlconf2session" . "\n\t}"; } else { $varsqlconfsession = 'radutmp'; } // post-auth section DATABASE 1 if (($sqlconf['varsqlconfincludeenable'] == 'on') && ($sqlconf['varsqlconfenablepostauth'] == 'Enable')) { $varsqlconfpostauth = "$varsqlconf2failover {" . "\n\t\t\tsql" . "\n\t\t\t$varsqlconf2postauth" . "\n\t}"; } else { $varsqlconfpostauth = '### sql DISABLED ###'; } // Changing authorize section for plain mac auth // Variables: If not using 802.1x, mac address must be known $varsettings = $config['installedpackages']['freeradiussettings']['config'][0]; // If unchecked we need the normal EAP section. if (!$varsettings['varsettingsenablemacauth']) { $varplainmacauthenable = '##### AUTHORIZE FOR PLAIN MAC-AUTH IS DISABLED #####'; $varplainmacpreacctenable = '##### ACCOUNTING FOR PLAIN MAC-AUTH DISABLED #####'; } // If checked we need to check if it is plain mac or eap else { $varplainmacauthenable = ''; $varplainmacauthenable .= "### FIRST check MAC address in authorized_macs and if that fails proceed with other checks below in else-section ###"; $varplainmacauthenable .= "\n\t### if cleaning up the Calling-Station-Id...###"; $varplainmacauthenable .= "\n\trewrite_calling_station_id"; $varplainmacauthenable .= "\n\t"; $varplainmacauthenable .= "\n\t# now check against the authorized_macs file"; $varplainmacauthenable .= "\n\tauthorized_macs"; $varplainmacauthenable .= "\n\tif (ok) {"; $varplainmacauthenable .= "\n\t\t\tupdate control {"; $varplainmacauthenable .= "\n\t\t\tAuth-Type := Accept"; $varplainmacauthenable .= "\n\t\t}"; $varplainmacauthenable .= "\n\t}"; $varplainmacauthenable .= "\n\t### Here we have to place all other authorize modules which should be check when MAC fails ###"; $varplainmacpreacctenable = ''; $varplainmacpreacctenable .= '##### ACCOUNTING FOR PLAIN MAC-AUTH ENABLED #####'; $varplainmacpreacctenable .= "\n\trewrite_calling_station_id"; } // Disable acct_unique in preacct section $varsettings = $config['installedpackages']['freeradiussettings']['config'][0]; if ($varsettings['varsettingsenableacctunique'] == 'on') { $varsettingsacctuniqueenabled = '##### DISABLE acct_unique DISABLE #####'; } else { $varsettingsacctuniqueenabled = 'acct_unique'; } $conf .= <<<EOD ###################################################################### # # As of 2.0.0, FreeRADIUS supports virtual hosts using the # "server" section, and configuration directives. # # Virtual hosts should be put into the "sites-available" # directory. Soft links should be created in the "sites-enabled" # directory to these files. This is done in a normal installation. # # If you are using 802.1X (EAP) authentication, please see also # the "inner-tunnel" virtual server. You wll likely have to edit # that, too, for authentication to work. # # $Id$ # ###################################################################### # # Read "man radiusd" before editing this file. See the section # titled DEBUGGING. It outlines a method where you can quickly # obtain the configuration you want, without running into # trouble. See also "man unlang", which documents the format # of this file. # # This configuration is designed to work in the widest possible # set of circumstances, with the widest possible number of # authentication methods. This means that in general, you should # need to make very few changes to this file. # # The best way to configure the server for your local system # is to CAREFULLY edit this file. Most attempts to make large # edits to this file will BREAK THE SERVER. Any edits should # be small, and tested by running the server with "radiusd -X". # Once the edits have been verified to work, save a copy of these # configuration files somewhere. (e.g. as a "tar" file). Then, # make more edits, and test, as above. # # There are many "commented out" references to modules such # as ldap, sql, etc. These references serve as place-holders. # If you need the functionality of that module, then configure # it in radiusd.conf, and un-comment the references to it in # this file. In most cases, those small changes will result # in the server being able to connect to the DB, and to # authenticate users. # ###################################################################### # # In 1.x, the "authorize", etc. sections were global in # radiusd.conf. As of 2.0, they SHOULD be in a server section. # # The server section with no virtual server name is the "default" # section. It is used when no server name is specified. # # We don't indent the rest of this file, because doing so # would make it harder to read. # # Authorization. First preprocess (hints and huntgroups files), # then realms, and finally look in the "users" file. # # Any changes made here should also be made to the "inner-tunnel" # virtual server. # # The order of the realm modules will determine the order that # we try to find a matching realm. # # Make *sure* that 'preprocess' comes before any realm if you # need to setup hints for the remote radius server authorize { # # Security settings. Take a User-Name, and do some simple # checks on it, for spaces and other invalid characters. If # it looks like the user is trying to play games, reject it. # # This should probably be enabled by default. # # See policy.conf for the definition of the filter_username policy. # # filter_username # # The preprocess module takes care of sanitizing some bizarre # attributes in the request, and turning them into attributes # which are more standard. # # It takes care of processing the 'raddb/hints' and the # 'raddb/huntgroups' files. preprocess # # $varplainmacauthenable # # If you want to have a log of authentication requests, # un-comment the following line, and the 'detail auth_log' # section, above. # auth_log # # The chap module will set 'Auth-Type := CHAP' if we are # handling a CHAP request and Auth-Type has not already been set chap # # If the users are logging in with an MS-CHAP-Challenge # attribute for authentication, the mschap module will find # the MS-CHAP-Challenge attribute, and add 'Auth-Type := MS-CHAP' # to the request, which will cause the server to then use # the mschap module for authentication. mschap # # If you have a Cisco SIP server authenticating against # FreeRADIUS, uncomment the following line, and the 'digest' # line in the 'authenticate' section. digest # # The WiMAX specification says that the Calling-Station-Id # is 6 octets of the MAC. This definition conflicts with # RFC 3580, and all common RADIUS practices. Un-commenting # the "wimax" module here means that it will fix the # Calling-Station-Id attribute to the normal format as # specified in RFC 3580 Section 3.21 # wimax # # Look for IPASS style 'realm/', and if not found, look for # '@realm', and decide whether or not to proxy, based on # that. # IPASS # # If you are using multiple kinds of realms, you probably # want to set "ignore_null = yes" for all of them. # Otherwise, when the first style of realm doesn't match, # the other styles won't be checked. # suffix ntdomain # # This module takes care of EAP-MD5, EAP-TLS, and EAP-LEAP # authentication. # # It also sets the EAP-Type attribute in the request # attribute list to the EAP type from the packet. # # As of 2.0, the EAP module returns "ok" in the authorize stage # for TTLS and PEAP. In 1.x, it never returned "ok" here, so # this change is compatible with older configurations. # # The example below uses module failover to avoid querying all # of the following modules if the EAP module returns "ok". # Therefore, your LDAP and/or SQL servers will not be queried # for the many packets that go back and forth to set up TTLS # or PEAP. The load on those servers will therefore be reduced. # # eap { ok = return } # # Pull crypt'd passwords from /etc/passwd or /etc/shadow, # using the system API's to get the password. If you want # to read /etc/passwd or /etc/shadow directly, see the # passwd module in radiusd.conf. # # unix # # Read the 'users' file files # # Look in an SQL database. The schema of the database # is meant to mirror the "users" file. # # See "Authorization Queries" in sql.conf $varsqlconfauthorize # # If you are using /etc/smbpasswd, and are also doing # mschap authentication, the un-comment this line, and # configure the 'etc_smbpasswd' module, above. # etc_smbpasswd # # The ldap module will set Auth-Type to LDAP if it has not # already been set $varmodulesldapenableauthorize # # Enforce daily limits on time spent logged in. daily weekly monthly forever # # Use the checkval module checkval expiration logintime # # If no other module has claimed responsibility for # authentication, then try to use PAP. This allows the # other modules listed above to add a "known good" password # to the request, and to do nothing else. The PAP module # will then see that password, and use it to do PAP # authentication. # # This module should be listed last, so that the other modules # get a chance to set Auth-Type for themselves. # pap # # If "status_server = yes", then Status-Server messages are passed # through the following section, and ONLY the following section. # This permits you to do DB queries, for example. If the modules # listed here return "fail", then NO response is sent. # Autz-Type Status-Server { } } # Authentication. # # # This section lists which modules are available for authentication. # Note that it does NOT mean 'try each module in order'. It means # that a module from the 'authorize' section adds a configuration # attribute 'Auth-Type := FOO'. That authentication type is then # used to pick the apropriate module from the list below. # # In general, you SHOULD NOT set the Auth-Type attribute. The server # will figure it out on its own, and will do the right thing. The # most common side effect of erroneously setting the Auth-Type # attribute is that one authentication method will work, but the # others will not. # # The common reasons to set the Auth-Type attribute by hand # is to either forcibly reject the user (Auth-Type := Reject), # or to or forcibly accept the user (Auth-Type := Accept). # # Note that Auth-Type := Accept will NOT work with EAP. # # Please do not put "unlang" configurations into the "authenticate" # section. Put them in the "post-auth" section instead. That's what # the post-auth section is for. # authenticate { # # PAP authentication, when a back-end database listed # in the 'authorize' section supplies a password. The # password can be clear-text, or encrypted. Auth-Type PAP { pap } # # Most people want CHAP authentication # A back-end database listed in the 'authorize' section # MUST supply a CLEAR TEXT password. Encrypted passwords # won't work. Auth-Type CHAP { chap } # # MSCHAP authentication. Auth-Type MS-CHAP { mschap } # # Mobile-One-Time-Password (MOTP) authentication. Auth-Type MOTP { motp } # # If you have a Cisco SIP server authenticating against # FreeRADIUS, uncomment the following line, and the 'digest' # line in the 'authorize' section. digest # # Pluggable Authentication Modules. # pam # # See 'man getpwent' for information on how the 'unix' # module checks the users password. Note that packets # containing CHAP-Password attributes CANNOT be authenticated # against /etc/passwd! See the FAQ for details. # # For normal "crypt" authentication, the "pap" module should # be used instead of the "unix" module. The "unix" module should # be used for authentication ONLY for compatibility with legacy # FreeRADIUS configurations. # unix # Uncomment it if you want to use ldap for authentication # # Note that this means "check plain-text password against # the ldap database", which means that EAP won't work, # as it does not supply a plain-text password. $varmodulesldapenableauthenticate # # Allow EAP authentication. eap # # The older configurations sent a number of attributes in # Access-Challenge packets, which wasn't strictly correct. # If you want to filter out these attributes, uncomment # the following lines. # # Auth-Type eap { # eap { # handled = 1 # } # if (handled && (Response-Packet-Type == Access-Challenge)) { # attr_filter.access_challenge.post-auth # handled # override the "updated" code from attr_filter # } # } } # # Pre-accounting. Decide which accounting type to use. # preacct { preprocess $varplainmacpreacctenable # # Session start times are *implied* in RADIUS. # The NAS never sends a "start time". Instead, it sends # a start packet, *possibly* with an Acct-Delay-Time. # The server is supposed to conclude that the start time # was "Acct-Delay-Time" seconds in the past. # # The code below creates an explicit start time, which can # then be used in other modules. # # The start time is: NOW - delay - session_length # update request { FreeRADIUS-Acct-Session-Start-Time = "%{expr: %l - %{%{Acct-Session-Time}:-0} - %{%{Acct-Delay-Time}:-0}}" } # # Ensure that we have a semi-unique identifier for every # request, and many NAS boxes are broken. $varsettingsacctuniqueenabled # # Look for IPASS-style 'realm/', and if not found, look for # '@realm', and decide whether or not to proxy, based on # that. # # Accounting requests are generally proxied to the same # home server as authentication requests. # IPASS suffix ntdomain # # Read the 'acct_users' file files } # # Accounting. Log the accounting data. # accounting { # # Create a 'detail'ed log of the packets. # Note that accounting requests which are proxied # are also logged in the detail file. detail daily weekly monthly forever ### This makes it possible to run the datacounter_acct module only on accounting-stop and interim-updates if ((request:Acct-Status-Type == Stop) || (request:Acct-Status-Type == Interim-Update)) { datacounterdaily datacounterweekly datacountermonthly datacounterforever } # Update the wtmp file # # If you don't use "radlast", you can delete this line. unix # # For Simultaneous-Use tracking. # # Due to packet losses in the network, the data here # may be incorrect. There is little we can do about it. radutmp # sradutmp # Return an address to the IP Pool when we see a stop record. # main_pool # # Log traffic to an SQL database. # # See "Accounting queries" in sql.conf $varsqlconfaccounting # # If you receive stop packets with zero session length, # they will NOT be logged in the database. The SQL module # will print a message (only in debugging mode), and will # return "noop". # # You can ignore these packets by uncommenting the following # three lines. Otherwise, the server will not respond to the # accounting request, and the NAS will retransmit. # # if (noop) { # ok # } # # Instead of sending the query to the SQL server, # write it into a log file. # # sql_log # Cisco VoIP specific bulk accounting # pgsql-voip # For Exec-Program and Exec-Program-Wait exec # Filter attributes from the accounting response. attr_filter.accounting_response # # See "Autz-Type Status-Server" for how this works. # Acct-Type Status-Server { } } # Session database, used for checking Simultaneous-Use. Either the radutmp # or rlm_sql module can handle this. # The rlm_sql module is *much* faster session { ### choose radutmp or sql $varsqlconfsession } # Post-Authentication # Once we KNOW that the user has been authenticated, there are # additional steps we can take. post-auth { # Get an address from the IP Pool. # main_pool # # If you want to have a log of authentication replies, # un-comment the following line, and the 'detail reply_log' # section, above. # reply_log # # After authenticating the user, do another SQL query. # # See "Authentication Logging Queries" in sql.conf $varsqlconfpostauth # # Instead of sending the query to the SQL server, # write it into a log file. # # sql_log # # Un-comment the following if you have set # 'edir_account_policy_check = yes' in the ldap module sub-section of # the 'modules' section. # # ldap # For Exec-Program and Exec-Program-Wait exec # # Calculate the various WiMAX keys. In order for this to work, # you will need to define the WiMAX NAI, usually via # # update request { # WiMAX-MN-NAI = "%{User-Name}" # } # # If you want various keys to be calculated, you will need to # update the reply with "template" values. The module will see # this, and replace the template values with the correct ones # taken from the cryptographic calculations. e.g. # # update reply { # WiMAX-FA-RK-Key = 0x00 # WiMAX-MSK = "%{EAP-MSK}" # } # # You may want to delete the MS-MPPE-*-Keys from the reply, # as some WiMAX clients behave badly when those attributes # are included. See "raddb/modules/wimax", configuration # entry "delete_mppe_keys" for more information. # # wimax # If there is a client certificate (EAP-TLS, sometimes PEAP # and TTLS), then some attributes are filled out after the # certificate verification has been performed. These fields # MAY be available during the authentication, or they may be # available only in the "post-auth" section. # # The first set of attributes contains information about the # issuing certificate which is being used. The second # contains information about the client certificate (if # available). # # update reply { # Reply-Message += "%{TLS-Cert-Serial}" # Reply-Message += "%{TLS-Cert-Expiration}" # Reply-Message += "%{TLS-Cert-Subject}" # Reply-Message += "%{TLS-Cert-Issuer}" # Reply-Message += "%{TLS-Cert-Common-Name}" # # Reply-Message += "%{TLS-Client-Cert-Serial}" # Reply-Message += "%{TLS-Client-Cert-Expiration}" # Reply-Message += "%{TLS-Client-Cert-Subject}" # Reply-Message += "%{TLS-Client-Cert-Issuer}" # Reply-Message += "%{TLS-Client-Cert-Common-Name}" # } # If the WiMAX module did it's work, you may want to do more # things here, like delete the MS-MPPE-*-Key attributes. # # if (updated) { # update reply { # MS-MPPE-Recv-Key !* 0x00 # MS-MPPE-Send-Key !* 0x00 # } # } # # Access-Reject packets are sent through the REJECT sub-section of the # post-auth section. # # Add the ldap module name (or instance) if you have set # 'edir_account_policy_check = yes' in the ldap module configuration # Post-Auth-Type REJECT { # log failed authentications in SQL, too. # sql attr_filter.access_reject } } # # When the server decides to proxy a request to a home server, # the proxied request is first passed through the pre-proxy # stage. This stage can re-write the request, or decide to # cancel the proxy. # # Only a few modules currently have this method. # pre-proxy { # attr_rewrite # Uncomment the following line if you want to change attributes # as defined in the preproxy_users file. # files # Uncomment the following line if you want to filter requests # sent to remote servers based on the rules defined in the # 'attrs.pre-proxy' file. attr_filter.pre-proxy # If you want to have a log of packets proxied to a home # server, un-comment the following line, and the # 'detail pre_proxy_log' section, above. # pre_proxy_log } # # When the server receives a reply to a request it proxied # to a home server, the request may be massaged here, in the # post-proxy stage. # post-proxy { # If you want to have a log of replies from a home server, # un-comment the following line, and the 'detail post_proxy_log' # section, above. # post_proxy_log # attr_rewrite # Uncomment the following line if you want to filter replies from # remote proxies based on the rules defined in the 'attrs' file. attr_filter.post-proxy # # If you are proxying LEAP, you MUST configure the EAP # module, and you MUST list it here, in the post-proxy # stage. # # You MUST also use the 'nostrip' option in the 'realm' # configuration. Otherwise, the User-Name attribute # in the proxied request will not match the user name # hidden inside of the EAP packet, and the end server will # reject the EAP request. # eap # # If the server tries to proxy a request and fails, then the # request is processed through the modules in this section. # # The main use of this section is to permit robust proxying # of accounting packets. The server can be configured to # proxy accounting packets as part of normal processing. # Then, if the home server goes down, accounting packets can # be logged to a local "detail" file, for processing with # radrelay. When the home server comes back up, radrelay # will read the detail file, and send the packets to the # home server. # # With this configuration, the server always responds to # Accounting-Requests from the NAS, but only writes # accounting packets to disk if the home server is down. # # Post-Proxy-Type Fail { # detail # } } EOD; $filename = FREERADIUS_BASE . '/etc/raddb/sites-available/default'; conf_mount_rw(); file_put_contents($filename, $conf); chmod($filename, 0640); conf_mount_ro(); // No need to restart here because the restart of the service will be done in "freeradius_settings_resync" // restart_service('radiusd'); } function freeradius_cacertcnf_resync() { global $config; $conf = ''; $arrcerts = $config['installedpackages']['freeradiuscerts']['config'][0]; // General variables: CA, Server, Client $varcertsdefaultdays = ($arrcerts['varcertsdefaultdays']?$arrcerts['varcertsdefaultdays']:'3650'); $varcertsdefaultmd = ($arrcerts['varcertsdefaultmd']?$arrcerts['varcertsdefaultmd']:'md5'); $varcertsdefaultbits = ($arrcerts['varcertsdefaultbits']?$arrcerts['varcertsdefaultbits']:'2048'); $varcertspassword = ($arrcerts['varcertspassword']?$arrcerts['varcertspassword']:'whatever'); $varcertscountryname = ($arrcerts['varcertscountryname']?$arrcerts['varcertscountryname']:'US'); $varcertsstateorprovincename = ($arrcerts['varcertsstateorprovincename']?$arrcerts['varcertsstateorprovincename']:'Texas'); $varcertslocalityname = ($arrcerts['varcertslocalityname']?$arrcerts['varcertslocalityname']:'Austin'); $varcertsorganizationname = ($arrcerts['varcertsorganizationname']?$arrcerts['varcertsorganizationname']:'My Company Inc'); // Variables: Only for CA $varcertscaemailaddress = ($arrcerts['varcertscaemailaddress']?$arrcerts['varcertscaemailaddress']:'admin@mycompany.com'); $varcertscacommonname = ($arrcerts['varcertscacommonname']?$arrcerts['varcertscacommonname']:'internal-ca'); $conf .= <<<EOD [ ca ] default_ca = CA_default [ CA_default ] dir = ./ certs = \$dir crl_dir = \$dir/crl database = \$dir/index.txt new_certs_dir = \$dir certificate = \$dir/ca.pem serial = \$dir/serial crl = \$dir/crl.pem private_key = \$dir/ca.key RANDFILE = \$dir/.rand name_opt = ca_default cert_opt = ca_default default_days = $varcertsdefaultdays default_crl_days = 30 default_md = $varcertsdefaultmd preserve = no policy = policy_match [ policy_match ] countryName = match stateOrProvinceName = match organizationName = match organizationalUnitName = optional commonName = supplied emailAddress = optional [ policy_anything ] countryName = optional stateOrProvinceName = optional localityName = optional organizationName = optional organizationalUnitName = optional commonName = supplied emailAddress = optional [ req ] prompt = no distinguished_name = certificate_authority default_bits = $varcertsdefaultbits input_password = $varcertspassword output_password = $varcertspassword x509_extensions = v3_ca [certificate_authority] countryName = $varcertscountryname stateOrProvinceName = $varcertsstateorprovincename localityName = $varcertslocalityname organizationName = $varcertsorganizationname emailAddress = $varcertscaemailaddress commonName = "$varcertscacommonname" [v3_ca] subjectKeyIdentifier = hash authorityKeyIdentifier = keyid:always,issuer:always basicConstraints = CA:true EOD; $filename = FREERADIUS_BASE . '/etc/raddb/certs/ca.cnf'; conf_mount_rw(); file_put_contents($filename, $conf); chmod($filename, 0640); conf_mount_ro(); } function freeradius_servercertcnf_resync() { global $config; $conf = ''; $arrcerts = $config['installedpackages']['freeradiuscerts']['config'][0]; // General variables: CA, Server, Client $varcertsdefaultdays = ($arrcerts['varcertsdefaultdays']?$arrcerts['varcertsdefaultdays']:'3650'); $varcertsdefaultmd = ($arrcerts['varcertsdefaultmd']?$arrcerts['varcertsdefaultmd']:'md5'); $varcertsdefaultbits = ($arrcerts['varcertsdefaultbits']?$arrcerts['varcertsdefaultbits']:'2048'); $varcertspassword = ($arrcerts['varcertspassword']?$arrcerts['varcertspassword']:'whatever'); $varcertscountryname = ($arrcerts['varcertscountryname']?$arrcerts['varcertscountryname']:'US'); $varcertsstateorprovincename = ($arrcerts['varcertsstateorprovincename']?$arrcerts['varcertsstateorprovincename']:'Texas'); $varcertslocalityname = ($arrcerts['varcertslocalityname']?$arrcerts['varcertslocalityname']:'Austin'); $varcertsorganizationname = ($arrcerts['varcertsorganizationname']?$arrcerts['varcertsorganizationname']:'My Company Inc'); // Variables: Only for Server $varcertsserveremailaddress = ($arrcerts['varcertsserveremailaddress']?$arrcerts['varcertsserveremailaddress']:'webadmin@mycompany.com'); $varcertsservercommonname = ($arrcerts['varcertsservercommonname']?$arrcerts['varcertsservercommonname']:'server-cert'); $conf .= <<<EOD [ ca ] default_ca = CA_default [ CA_default ] dir = ./ certs = \$dir crl_dir = \$dir/crl database = \$dir/index.txt new_certs_dir = \$dir certificate = \$dir/server.pem serial = \$dir/serial crl = \$dir/crl.pem private_key = \$dir/server.key RANDFILE = \$dir/.rand name_opt = ca_default cert_opt = ca_default default_days = $varcertsdefaultdays default_crl_days = 30 default_md = $varcertsdefaultmd preserve = no policy = policy_match [ policy_match ] countryName = match stateOrProvinceName = match organizationName = match organizationalUnitName = optional commonName = supplied emailAddress = optional [ policy_anything ] countryName = optional stateOrProvinceName = optional localityName = optional organizationName = optional organizationalUnitName = optional commonName = supplied emailAddress = optional [ req ] prompt = no distinguished_name = server default_bits = $varcertsdefaultbits input_password = $varcertspassword output_password = $varcertspassword [server] countryName = $varcertscountryname stateOrProvinceName = $varcertsstateorprovincename localityName = $varcertslocalityname organizationName = $varcertsorganizationname emailAddress = $varcertsserveremailaddress commonName = "$varcertsservercommonname" EOD; $filename = FREERADIUS_BASE . '/etc/raddb/certs/server.cnf'; conf_mount_rw(); file_put_contents($filename, $conf); chmod($filename, 0640); conf_mount_ro(); } function freeradius_clientcertcnf_resync() { global $config; $conf = ''; $arrcerts = $config['installedpackages']['freeradiuscerts']['config'][0]; // General variables: CA, Server, Client $varcertsdefaultdays = ($arrcerts['varcertsdefaultdays']?$arrcerts['varcertsdefaultdays']:'3650'); $varcertsdefaultmd = ($arrcerts['varcertsdefaultmd']?$arrcerts['varcertsdefaultmd']:'md5'); $varcertsdefaultbits = ($arrcerts['varcertsdefaultbits']?$arrcerts['varcertsdefaultbits']:'2048'); $varcertspassword = ($arrcerts['varcertspassword']?$arrcerts['varcertspassword']:'whatever'); $varcertscountryname = ($arrcerts['varcertscountryname']?$arrcerts['varcertscountryname']:'US'); $varcertsstateorprovincename = ($arrcerts['varcertsstateorprovincename']?$arrcerts['varcertsstateorprovincename']:'Texas'); $varcertslocalityname = ($arrcerts['varcertslocalityname']?$arrcerts['varcertslocalityname']:'Austin'); $varcertsorganizationname = ($arrcerts['varcertsorganizationname']?$arrcerts['varcertsorganizationname']:'My Company Inc'); // Variables: Only for Client $varcertsclientemailaddress = ($arrcerts['varcertsclientemailaddress']?$arrcerts['varcertsclientemailaddress']:'user@mycompany.com'); $varcertsclientcommonname = ($arrcerts['varcertsclientcommonname']?$arrcerts['varcertsclientcommonname']:'client-cert'); $conf .= <<<EOD [ ca ] default_ca = CA_default [ CA_default ] dir = ./ certs = \$dir crl_dir = \$dir/crl database = \$dir/index.txt new_certs_dir = \$dir certificate = \$dir/server.pem serial = \$dir/serial crl = \$dir/crl.pem private_key = \$dir/server.key RANDFILE = \$dir/.rand name_opt = ca_default cert_opt = ca_default default_days = $varcertsdefaultdays default_crl_days = 30 default_md = $varcertsdefaultmd preserve = no policy = policy_match [ policy_match ] countryName = match stateOrProvinceName = match organizationName = match organizationalUnitName = optional commonName = supplied emailAddress = optional [ policy_anything ] countryName = optional stateOrProvinceName = optional localityName = optional organizationName = optional organizationalUnitName = optional commonName = supplied emailAddress = optional [ req ] prompt = no distinguished_name = client default_bits = $varcertsdefaultbits input_password = $varcertspassword output_password = $varcertspassword [client] countryName = $varcertscountryname stateOrProvinceName = $varcertsstateorprovincename localityName = $varcertslocalityname organizationName = $varcertsorganizationname emailAddress = $varcertsclientemailaddress commonName = "$varcertsclientcommonname" EOD; $filename = FREERADIUS_BASE . '/etc/raddb/certs/client.cnf'; conf_mount_rw(); file_put_contents($filename, $conf); chmod($filename, 0640); conf_mount_ro(); } function freeradius_allcertcnf_resync() { global $config; // We need to make this write enabled for embedded systems to write certs conf_mount_rw(); // Only proceed these steps if freeRADIUS Cert-Manager is activated. if pfSense cert manager is used skip this. $eapconf = $config['installedpackages']['freeradiuseapconf']['config'][0]; if ($eapconf['vareapconfchoosecertmanager'] == '') { $arrcerts = $config['installedpackages']['freeradiuscerts']['config'][0]; // General variable for deleting and generation of further Client-Cert $varcertscreateclient = ($arrcerts['varcertscreateclient']?$arrcerts['varcertscreateclient']:'no'); // General variables for deleting: CA, Server, Client $varcertsdeleteall = ($arrcerts['varcertsdeleteall']?$arrcerts['varcertsdeleteall']:'no'); // If all certs should be deleted, we do not need to delete and recreate client-certs first. if ($arrcerts['varcertsdeleteall'] == 'no') { if ($arrcerts['varcertscreateclient'] == 'yes') { // delete all old certificates and keys log_error("freeRADIUS: deleting all client.csr .crt .key .pem .tar in " . FREERADIUS_BASE . "/etc/raddb/certs"); exec("rm -f " . FREERADIUS_BASE . "/etc/raddb/certs/client.csr"); exec("rm -f " . FREERADIUS_BASE . "/etc/raddb/certs/client.crt"); exec("rm -f " . FREERADIUS_BASE . "/etc/raddb/certs/client.key"); exec("rm -f " . FREERADIUS_BASE . "/etc/raddb/certs/client.pem"); exec("rm -f " . FREERADIUS_BASE . "/etc/raddb/certs/client.tar"); // run fuction to create ONLY new client.cnf files based on user input from freeradiuscert.xml freeradius_clientcertcnf_resync(); // make bootstrap executable and run to create cert based on client.cnf files exec("chmod 0770 " . FREERADIUS_BASE . "/etc/raddb/certs/bootstrap"); exec(FREERADIUS_BASE . "/etc/raddb/certs/bootstrap"); // rename client generated XX.pem to client.pem // use regex to replace spaces and so on. $varserial = preg_replace("/\s/","",file_get_contents(FREERADIUS_BASE . '/etc/raddb/certs/serial.old')); if (file_exists(FREERADIUS_BASE . "/etc/raddb/certs/$varserial.pem")) rename(FREERADIUS_BASE . "/etc/raddb/certs/$varserial.pem",FREERADIUS_BASE . "/etc/raddb/certs/client.pem"); // tar client-cert files exec("cd " . FREERADIUS_BASE . "/etc/raddb/certs && tar -cf client.tar client.crt client.csr client.key ca.der client.pem"); // Make all files in certs folder read/write only for root exec("chmod -R 0600 " . FREERADIUS_BASE . "/etc/raddb/certs/"); log_error("freeRADIUS: Created new client.csr .crt .key .pem and added them together with ca.der in " . FREERADIUS_BASE . "/etc/raddb/certs/client.tar"); } } else { if ($arrcerts['varcertsdeleteall'] == 'yes') { // delete all old certificates and keys - deletes certs from pfsense cert-manager IN THIS FOLDER, too. log_error("freeRADIUS: deleting all CA, Server and Client certs, DH, random and database files in " . FREERADIUS_BASE . "/etc/raddb/certs"); exec("rm -f " . FREERADIUS_BASE . "/etc/raddb/certs/ca.pem && rm -f " . FREERADIUS_BASE . "/etc/raddb/certs/server.pem && rm -f " . FREERADIUS_BASE . "/etc/raddb/certs/client.pem"); exec("rm -f " . FREERADIUS_BASE . "/etc/raddb/certs/ca.der && rm -f " . FREERADIUS_BASE . "/etc/raddb/certs/server.der && rm -f " . FREERADIUS_BASE . "/etc/raddb/certs/client.der"); exec("rm -f " . FREERADIUS_BASE . "/etc/raddb/certs/ca.csr && rm -f " . FREERADIUS_BASE . "/etc/raddb/certs/server.csr && rm -f " . FREERADIUS_BASE . "/etc/raddb/certs/client.csr"); exec("rm -f " . FREERADIUS_BASE . "/etc/raddb/certs/ca.crt && rm -f " . FREERADIUS_BASE . "/etc/raddb/certs/server.crt && rm -f " . FREERADIUS_BASE . "/etc/raddb/certs/client.crt"); exec("rm -f " . FREERADIUS_BASE . "/etc/raddb/certs/ca.key && rm -f " . FREERADIUS_BASE . "/etc/raddb/certs/server.key && rm -f " . FREERADIUS_BASE . "/etc/raddb/certs/client.key"); exec("rm -f " . FREERADIUS_BASE . "/etc/raddb/certs/ca.p12 && rm -f " . FREERADIUS_BASE . "/etc/raddb/certs/server.p12 && rm -f " . FREERADIUS_BASE . "/etc/raddb/certs/client.p12"); exec("rm -f " . FREERADIUS_BASE . "/etc/raddb/certs/serial*"); exec("rm -f " . FREERADIUS_BASE . "/etc/raddb/certs/index*"); exec("rm -f " . FREERADIUS_BASE . "/etc/raddb/certs/dh"); exec("rm -f " . FREERADIUS_BASE . "/etc/raddb/certs/random"); exec("rm -f " . FREERADIUS_BASE . "/etc/raddb/certs/client.tar"); // run fuctions to create new .cnf files based on user input from freeradiuscert.xml freeradius_cacertcnf_resync(); freeradius_servercertcnf_resync(); freeradius_clientcertcnf_resync(); // this command deletes the pfsense_cert_mgr checkfile so when we change back to pfsense cert manager a new DH + random file will be created if (file_exists(FREERADIUS_BASE . "/etc/raddb/certs/pfsense_cert_mgr")) { unlink(FREERADIUS_BASE . "/etc/raddb/certs/pfsense_cert_mgr"); } // generate new DH and RANDOM file log_error("freeRADIUS: Creating new DH and random file in " . FREERADIUS_BASE . "/etc/raddb/certs"); exec("cd " . FREERADIUS_BASE . "/etc/raddb/certs && openssl dhparam -out dh 1024"); exec("cd " . FREERADIUS_BASE . "/etc/raddb/certs && dd if=/dev/urandom of=./random count=10"); log_error("freeRADIUS: Creating new CA, Server and Client certs in " . FREERADIUS_BASE . "/etc/raddb/certs"); // make bootstrap executable and run to create certs based on .cnf files exec("chmod 0770 " . FREERADIUS_BASE . "/etc/raddb/certs/bootstrap"); exec(FREERADIUS_BASE . "/etc/raddb/certs/bootstrap"); // rename client generated 02.pem to client.pem if (file_exists(FREERADIUS_BASE . "/etc/raddb/certs/02.pem")) rename(FREERADIUS_BASE . "/etc/raddb/certs/02.pem",FREERADIUS_BASE . "/etc/raddb/certs/client.pem"); // tar client-cert files exec("cd " . FREERADIUS_BASE . "/etc/raddb/certs && tar -cf client.tar client.crt client.csr client.key ca.der client.pem"); exec("chmod -R 0600 " . FREERADIUS_BASE . "/etc/raddb/certs/"); log_error("freeRADIUS: Added client.csr .crt .key .pem together with ca.der in " . FREERADIUS_BASE . "/etc/raddb/certs/client.tar"); // If there were changes on the certificates we need to restart freeradius restart_service('radiusd'); } } } //end choose pfSense cert-manager else { return; } // Read-only because of embedded systems conf_mount_ro(); } //end of function // ##### The following part is based on the code of pfblocker ##### /* Uses XMLRPC to synchronize the changes to a remote node */ function freeradius_sync_on_changes() { global $config, $g; if (is_array($config['installedpackages']['freeradiussync'])){ $synconchanges = $config['installedpackages']['freeradiussync']['config'][0]['varsyncenablexmlrpc']; $varsynctimeout = $config['installedpackages']['freeradiussync']['config'][0]['varsynctimeout']; } else { return; } // if checkbox is NOT checked do nothing switch ($synconchanges){ case "manual": if (is_array($config['installedpackages']['freeradiussync']['config'][0]['row'])){ $rs=$config['installedpackages']['freeradiussync']['config'][0]['row']; } else{ log_error("[FreeRADIUS]: xmlrpc sync is enabled but there is no hosts to push on FreeRADIUS config."); return; } break; case "auto": if (is_array($config['installedpackages']['carpsettings']) && is_array($config['installedpackages']['carpsettings']['config'])){ $system_carp=$config['installedpackages']['carpsettings']['config'][0]; $rs[0]['varsyncdestinenable']="on"; $rs[0]['varsyncprotocol']=($config['system']['webgui']['protocol']!=""?$config['system']['webgui']['protocol']:"https"); $rs[0]['varsyncipaddress']=$system_carp['synchronizetoip']; $rs[0]['varsyncpassword']=$system_carp['password']; $rs[0]['varsyncport']=($config['system']['webgui']['port']!=""?$config['system']['webgui']['port']:"443"); if (! is_ipaddr($system_carp['synchronizetoip'])){ log_error("[FreeRADIUS]: xmlrpc sync is enabled but there is no system backup hosts to push FreeRADIUS config."); return; } } else{ log_error("[FreeRADIUS]: xmlrpc sync is enabled but there is no system backup hosts to push FreeRADIUS config."); return; } break; default: return; break; } if (is_array($rs)){ log_error("[FreeRADIUS]: xmlrpc sync is starting with timeout {$varsynctimeout} seconds."); foreach($rs as $sh){ if($sh['varsyncdestinenable']){ $varsyncprotocol = $sh['varsyncprotocol']; $sync_to_ip = $sh['varsyncipaddress']; $password = $sh['varsyncpassword']; $varsyncport = $sh['varsyncport']; if($password && $sync_to_ip) freeradius_do_xmlrpc_sync($sync_to_ip, $password, $varsyncport, $varsyncprotocol,$varsynctimeout); else log_error("[FreeRADIUS]: XMLRPC Sync with {$sh['varsyncipaddress']} has incomplete credentials. No XMLRPC Sync done!"); } else { log_error("[FreeRADIUS]: XMLRPC Sync with {$sh['varsyncipaddress']} is disabled"); } } log_error("[FreeRADIUS]: xmlrpc sync is ending."); } } /* Do the actual XMLRPC sync */ function freeradius_do_xmlrpc_sync($sync_to_ip, $password, $varsyncport, $varsyncprotocol,$varsynctimeout) { global $config, $g; if($varsynctimeout == '' || $varsynctimeout == 0) $varsynctimeout = 150; if(!$password) return; if(!$sync_to_ip) return; if(!$varsyncport) return; if(!$varsyncprotocol) return; // Check and choose correct protocol type, port number and IP address $synchronizetoip .= "$varsyncprotocol" . '://'; $port = "$varsyncport"; $synchronizetoip .= $sync_to_ip; /* xml will hold the sections to sync */ $xml = array(); $xml['freeradius'] = $config['installedpackages']['freeradius']; $xml['freeradiusauthorizedmacs'] = $config['installedpackages']['freeradiusauthorizedmacs']; $xml['freeradiusclients'] = $config['installedpackages']['freeradiusclients']; /* assemble xmlrpc payload */ $params = array( XML_RPC_encode($password), XML_RPC_encode($xml) ); /* set a few variables needed for sync code borrowed from filter.inc */ $url = $synchronizetoip; log_error("[FreeRADIUS]: Beginning FreeRADIUS XMLRPC sync with {$url}:{$port}."); $method = 'pfsense.merge_installedpackages_section_xmlrpc'; $msg = new XML_RPC_Message($method, $params); $cli = new XML_RPC_Client('/xmlrpc.php', $url, $port); $cli->setCredentials('admin', $password); if($g['debug']) $cli->setDebug(1); /* send our XMLRPC message and timeout after $varsynctimeout seconds */ $resp = $cli->send($msg, $varsynctimeout); if(!$resp) { $error = "A communications error occurred while FreeRADIUS was attempting XMLRPC sync with {$url}:{$port}."; log_error("[FreeRADIUS]: $error"); file_notice("sync_settings", $error, "FreeRADIUS Settings Sync", ""); } elseif($resp->faultCode()) { $cli->setDebug(1); $resp = $cli->send($msg, $varsynctimeout); $error = "An error code was received while FreeRADIUS XMLRPC was attempting to sync with {$url}:{$port} - Code " . $resp->faultCode() . ": " . $resp->faultString(); log_error("[FreeRADIUS]: $error"); file_notice("sync_settings", $error, "FreeRADIUS Settings Sync", ""); } else { log_error("[FreeRADIUS]: XMLRPC has synced data successfully with {$url}:{$port}."); } /* tell FreeRADIUS to reload our settings on the destionation sync host. */ $method = 'pfsense.exec_php'; $execcmd = "require_once('/usr/local/pkg/freeradius.inc');\n"; // pfblocker just needed one fuction to reload after XMLRPC. FreeRADIUS needs more so we point to a fuction below which contains all fuctions $execcmd .= "freeradius_all_after_XMLRPC_resync();"; /* assemble xmlrpc payload */ $params = array( XML_RPC_encode($password), XML_RPC_encode($execcmd) ); log_error("[FreeRADIUS]: XMLRPC is reloading data on {$url}:{$port}."); $msg = new XML_RPC_Message($method, $params); $cli = new XML_RPC_Client('/xmlrpc.php', $url, $port); $cli->setCredentials('admin', $password); $resp = $cli->send($msg, $varsynctimeout); if(!$resp) { $error = "A communications error occurred while FreeRADIUS was attempting XMLRPC sync with {$url}:{$port} (exec_php)."; log_error($error); file_notice("sync_settings", $error, "FreeRADIUS Settings Sync", ""); } elseif($resp->faultCode()) { $cli->setDebug(1); $resp = $cli->send($msg, $varsynctimeout); $error = "An error code was received while FreeRADIUS XMLRPC was attempting to sync with {$url}:{$port} - Code " . $resp->faultCode() . ": " . $resp->faultString(); log_error($error); file_notice("sync_settings", $error, "FreeRADIUS Settings Sync", ""); } else { log_error("[FreeRADIUS]: XMLRPC has reloaded data successfully on {$url}:{$port} (exec_php)."); } } // This function restarts all other needed functions after XMLRPC so that the content of .XML + .INC will be written in the files (clients.conf, users) // Adding more functions will increase the to sync function freeradius_all_after_XMLRPC_resync() { freeradius_users_resync(); freeradius_authorizedmacs_resync(); freeradius_clients_resync(); log_error("FreeRADIUS: Finished XMLRPC process. It should be OK. For more information look at the host which started sync."); exec(FREERADIUS_BASE . "/etc/rc.d/radiusd onerestart"); } function freeradius_modulescounter_resync() { global $config; $conf = ''; $conf .= <<<EOD # -*- text -*- # # $Id$ # counter module: # This module takes an attribute (count-attribute). # It also takes a key, and creates a counter for each unique # key. The count is incremented when accounting packets are # received by the server. The value of the increment depends # on the attribute type. # If the attribute is Acct-Session-Time or of an integer type we add # the value of the attribute. If it is anything else we increase the # counter by one. # # The 'reset' parameter defines when the counters are all reset to # zero. It can be hourly, daily, weekly, monthly or never. # # hourly: Reset on 00:00 of every hour # daily: Reset on 00:00:00 every day # weekly: Reset on 00:00:00 on sunday # monthly: Reset on 00:00:00 of the first day of each month # # It can also be user defined. It should be of the form: # num[hdwm] where: # h: hours, d: days, w: weeks, m: months # If the letter is ommited days will be assumed. In example: # reset = 10h (reset every 10 hours) # reset = 12 (reset every 12 days) # # # The check-name attribute defines an attribute which will be # registered by the counter module and can be used to set the # maximum allowed value for the counter after which the user # is rejected. # Something like: # # DEFAULT Max-Daily-Session := 36000 # Fall-Through = 1 # # You should add the counter module in the instantiate # section so that it registers check-name before the files # module reads the users file. # # If check-name is set and the user is to be rejected then we # send back a Reply-Message and we log a Failure-Message in # the radius.log # # If the count attribute is Acct-Session-Time then on each # login we send back the remaining online time as a # Session-Timeout attribute ELSE and if the reply-name is # set, we send back that attribute. The reply-name attribute # MUST be of an integer type. # # The counter-name can also be used instead of using the check-name # like below: # # DEFAULT Daily-Session-Time > 3600, Auth-Type = Reject # Reply-Message = "You've used up more than one hour today" # # The allowed-servicetype attribute can be used to only take # into account specific sessions. For example if a user first # logs in through a login menu and then selects ppp there will # be two sessions. One for Login-User and one for Framed-User # service type. We only need to take into account the second one. # # The module should be added in the instantiate, authorize and # accounting sections. Make sure that in the authorize # section it comes after any module which sets the # 'check-name' attribute. # counter daily { filename = /var/log/radacct/timecounter/db.daily key = User-Name count-attribute = Acct-Session-Time reset = daily counter-name = Daily-Session-Time check-name = Max-Daily-Session reply-name = Session-Timeout cache-size = 5000 } counter weekly { filename = /var/log/radacct/timecounter/db.weekly key = User-Name count-attribute = Acct-Session-Time reset = weekly counter-name = Weekly-Session-Time check-name = Max-Weekly-Session reply-name = Session-Timeout cache-size = 5000 } counter monthly { filename = /var/log/radacct/timecounter/db.monthly key = User-Name count-attribute = Acct-Session-Time reset = monthly counter-name = Monthly-Session-Time check-name = Max-Monthly-Session reply-name = Session-Timeout cache-size = 5000 } counter forever { filename = /var/log/radacct/timecounter/db.forever key = User-Name count-attribute = Acct-Session-Time reset = never counter-name = Forever-Session-Time check-name = Max-Forever-Session reply-name = Session-Timeout cache-size = 5000 } EOD; $filename = FREERADIUS_BASE . '/etc/raddb/modules/counter'; conf_mount_rw(); file_put_contents($filename, $conf); chmod($filename, 0640); conf_mount_ro(); } function freeradius_modulesmschap_resync() { global $config; $conf = ''; $conf .= <<<EOD # -*- text -*- # # $Id$ # Microsoft CHAP authentication # # This module supports MS-CHAP and MS-CHAPv2 authentication. # It also enforces the SMB-Account-Ctrl attribute. # mschap { # # If you are using /etc/smbpasswd, see the 'passwd' # module for an example of how to use /etc/smbpasswd # if use_mppe is not set to no mschap will # add MS-CHAP-MPPE-Keys for MS-CHAPv1 and # MS-MPPE-Recv-Key/MS-MPPE-Send-Key for MS-CHAPv2 # # use_mppe = no # if mppe is enabled require_encryption makes # encryption moderate # # require_encryption = yes # require_strong always requires 128 bit key # encryption # # require_strong = yes # Windows sends us a username in the form of # DOMAIN\user, but sends the challenge response # based on only the user portion. This hack # corrects for that incorrect behavior. # with_ntdomain_hack = yes # The module can perform authentication itself, OR # use a Windows Domain Controller. This configuration # directive tells the module to call the ntlm_auth # program, which will do the authentication, and return # the NT-Key. Note that you MUST have "winbindd" and # "nmbd" running on the local machine for ntlm_auth # to work. See the ntlm_auth program documentation # for details. # # If ntlm_auth is configured below, then the mschap # module will call ntlm_auth for every MS-CHAP # authentication request. If there is a cleartext # or NT hashed password available, you can set # "MS-CHAP-Use-NTLM-Auth := No" in the control items, # and the mschap module will do the authentication itself, # without calling ntlm_auth. # # Be VERY careful when editing the following line! # # You can also try setting the user name as: # # ... --username=%{mschap:User-Name} ... # # In that case, the mschap module will look at the User-Name # attribute, and do prefix/suffix checks in order to obtain # the "best" user name for the request. # # ntlm_auth = "/path/to/ntlm_auth --request-nt-key --username=%{%{Stripped-User-Name}:-%{%{User-Name}:-None}} --challenge=%{%{mschap:Challenge}:-00} -- nt-response=%{%{mschap:NT-Response}:-00}" # For Apple Server, when running on the same machine as # Open Directory. It has no effect on other systems. # # use_open_directory = yes # On failure, set (or not) the MS-CHAP error code saying # "retries allowed". # allow_retry = yes # An optional retry message. # retry_msg = "Re-enter (or reset) the password" } EOD; $filename = FREERADIUS_BASE . '/etc/raddb/modules/mschap'; conf_mount_rw(); file_put_contents($filename, $conf); chmod($filename, 0640); conf_mount_ro(); } function freeradius_modulesrealm_resync() { global $config; $conf = ''; $conf .= <<<EOD # 'realm/username' # Using this entry, IPASS users have their realm set to "IPASS". realm IPASS { format = prefix delimiter = "/" ignore_null = yes ignore_default = no } # 'username@realm' realm suffix { format = suffix delimiter = "@" ignore_null = yes ignore_default = no } # 'username%realm' realm realmpercent { format = suffix delimiter = "%" ignore_null = yes ignore_default = no } # 'domain\user' realm ntdomain { format = prefix ### 3 backslash in .inc will be 2 backslash in file and after starting radiusd just only one delimiter = "\\\" ignore_null = yes ignore_default = no } EOD; $filename = FREERADIUS_BASE . '/etc/raddb/modules/realm'; conf_mount_rw(); file_put_contents($filename, $conf); chmod($filename, 0640); conf_mount_ro(); } function freeradius_modulesldap_resync() { global $config; $conf = ''; $arrmodulesldap = $config['installedpackages']['freeradiusmodulesldap']['config'][0]; // Enable and Disable LDAP for "authorize" and "authenticate" will be done in "freeradius_serverdefault_resync" // redundatnt-load-balancing will there be done, too // Variables for General Configuration ldap1 $varmodulesldapserver = ($arrmodulesldap['varmodulesldapserver']?$arrmodulesldap['varmodulesldapserver']:'ldap.your.domain'); $varmodulesldapidentity = ($arrmodulesldap['varmodulesldapidentity']?$arrmodulesldap['varmodulesldapidentity']:'cn=admin,o=My Org,c=UA'); $varmodulesldappassword = ($arrmodulesldap['varmodulesldappassword']?$arrmodulesldap['varmodulesldappassword']:'mypass'); $varmodulesldapbasedn = ($arrmodulesldap['varmodulesldapbasedn']?$arrmodulesldap['varmodulesldapbasedn']:'o=My Org,c=UA'); $varmodulesldapfilter = ($arrmodulesldap['varmodulesldapfilter']?$arrmodulesldap['varmodulesldapfilter']:'(uid=%{%{Stripped-User-Name}:-%{User-Name}})'); $varmodulesldapbasefilter = ($arrmodulesldap['varmodulesldapbasefilter']?$arrmodulesldap['varmodulesldapbasefilter']:'(objectclass=radiusprofile)'); $varmodulesldapldapconnectionsnumber = ($arrmodulesldap['varmodulesldapldapconnectionsnumber']?$arrmodulesldap['varmodulesldapldapconnectionsnumber']:'5'); $varmodulesldaptimeout = ($arrmodulesldap['varmodulesldaptimeout']?$arrmodulesldap['varmodulesldaptimeout']:'4'); $varmodulesldaptimelimit = ($arrmodulesldap['varmodulesldaptimelimit']?$arrmodulesldap['varmodulesldaptimelimit']:'3'); $varmodulesldapnettimeout = ($arrmodulesldap['varmodulesldapnettimeout']?$arrmodulesldap['varmodulesldapnettimeout']:'1'); // Variables for General Configuration ldap2 $varmodulesldap2server = ($arrmodulesldap['varmodulesldap2server']?$arrmodulesldap['varmodulesldap2server']:'ldap.your.domain'); $varmodulesldap2identity = ($arrmodulesldap['varmodulesldap2identity']?$arrmodulesldap['varmodulesldap2identity']:'cn=admin,o=My Org,c=UA'); $varmodulesldap2password = ($arrmodulesldap['varmodulesldap2password']?$arrmodulesldap['varmodulesldap2password']:'mypass'); $varmodulesldap2basedn = ($arrmodulesldap['varmodulesldap2basedn']?$arrmodulesldap['varmodulesldap2basedn']:'o=My Org,c=UA'); $varmodulesldap2filter = ($arrmodulesldap['varmodulesldap2filter']?$arrmodulesldap['varmodulesldap2filter']:'(uid=%{%{Stripped-User-Name}:-%{User-Name}})'); $varmodulesldap2basefilter = ($arrmodulesldap['varmodulesldap2basefilter']?$arrmodulesldap['varmodulesldap2basefilter']:'(objectclass=radiusprofile)'); $varmodulesldap2ldapconnectionsnumber = ($arrmodulesldap['varmodulesldap2ldapconnectionsnumber']?$arrmodulesldap['varmodulesldap2ldapconnectionsnumber']:'5'); $varmodulesldap2timeout = ($arrmodulesldap['varmodulesldap2timeout']?$arrmodulesldap['varmodulesldap2timeout']:'4'); $varmodulesldap2timelimit = ($arrmodulesldap['varmodulesldap2timelimit']?$arrmodulesldap['varmodulesldap2timelimit']:'3'); $varmodulesldap2nettimeout = ($arrmodulesldap['varmodulesldap2nettimeout']?$arrmodulesldap['varmodulesldap2nettimeout']:'1'); // Variables for TLS / Certificates - ldap1 $varmodulesldaprequirecert = ($arrmodulesldap['varmodulesldaprequirecert']?$arrmodulesldap['varmodulesldaprequirecert']:'never'); // if enabled then create the certs in ../raddb/certs/ and enable "Start_tls" in ldap1 module if($arrmodulesldap['varmodulesldapenabletlssupport'] == 'on') { $ca_cert = lookup_ca($arrmodulesldap["ssl_ca_cert1"]); if ($ca_cert != false) { if(base64_decode($ca_cert['prv'])) { file_put_contents(FREERADIUS_BASE . "/etc/raddb/certs/ca_ldap1_key.pem", base64_decode($ca_cert['prv'])); $conf['ssl_ca_key'] = FREERADIUS_BASE . '/etc/raddb/certs/ca_ldap1_key.pem'; } if(base64_decode($ca_cert['crt'])) { file_put_contents(FREERADIUS_BASE . "/etc/raddb/certs/ca_ldap1_cert.pem", base64_decode($ca_cert['crt'])); $conf['ssl_ca_cert1'] = FREERADIUS_BASE . "/etc/raddb/certs/ca_ldap1_cert.pem"; } $svr_cert = lookup_cert($arrmodulesldap["ssl_server_cert1"]); if ($svr_cert != false) { if(base64_decode($svr_cert['prv'])) { file_put_contents(FREERADIUS_BASE . "/etc/raddb/certs/radius_ldap1_cert.key", base64_decode($svr_cert['prv'])); $conf['ssl_key'] = FREERADIUS_BASE . '/etc/raddb/certs/radius_ldap1_cert.key'; } } if(base64_decode($svr_cert['crt'])) { file_put_contents(FREERADIUS_BASE . "/etc/raddb/certs/radius_ldap1_cert.crt", base64_decode($svr_cert['crt'])); $conf['ssl_server_cert1'] = FREERADIUS_BASE . "/etc/raddb/certs/radius_ldap1_cert.crt"; } $conf['ssl_cert_dir'] = FREERADIUS_BASE . '/etc/raddb/certs'; } $varmodulesldapstarttls = "yes"; } else { $varmodulesldapstarttls = "no"; } // Variables for TLS / Certificates - ldap2 $varmodulesldap2requirecert = ($arrmodulesldap['varmodulesldap2requirecert']?$arrmodulesldap['varmodulesldap2requirecert']:'never'); // if enabled then create the certs in ../raddb/certs/ and enable "Start_tls" in ldap2 module if($arrmodulesldap['varmodulesldap2enabletlssupport'] == 'on') { $ca_cert = lookup_ca($arrmodulesldap["ssl_ca_cert2"]); if ($ca_cert != false) { if(base64_decode($ca_cert['prv'])) { file_put_contents(FREERADIUS_BASE . "/etc/raddb/certs/ca_ldap2_key.pem", base64_decode($ca_cert['prv'])); $conf['ssl_ca_key'] = FREERADIUS_BASE . '/etc/raddb/certs/ca_ldap2_key.pem'; } if(base64_decode($ca_cert['crt'])) { file_put_contents(FREERADIUS_BASE . "/etc/raddb/certs/ca_ldap2_cert.pem", base64_decode($ca_cert['crt'])); $conf['ssl_ca_cert2'] = FREERADIUS_BASE . "/etc/raddb/certs/ca_ldap2_cert.pem"; } $svr_cert = lookup_cert($arrmodulesldap["ssl_server_cert2"]); if ($svr_cert != false) { if(base64_decode($svr_cert['prv'])) { file_put_contents(FREERADIUS_BASE . "/etc/raddb/certs/radius_ldap2_cert.key", base64_decode($svr_cert['prv'])); $conf['ssl_key'] = FREERADIUS_BASE . '/etc/raddb/certs/radius_ldap2_cert.key'; } } if(base64_decode($svr_cert['crt'])) { file_put_contents(FREERADIUS_BASE . "/etc/raddb/certs/radius_ldap2_cert.crt", base64_decode($svr_cert['crt'])); $conf['ssl_server_cert2'] = FREERADIUS_BASE . "/etc/raddb/certs/radius_ldap2_cert.crt"; } $conf['ssl_cert_dir'] = FREERADIUS_BASE . '/etc/raddb/certs'; } $varmodulesldap2starttls = "yes"; } else { $varmodulesldap2starttls = "no"; } // Miscellaneous Configuration + MS Active Directory Compatibility ldap1 $varmodulesldapmsadcompatibilityenable = ($arrmodulesldap['varmodulesldapmsadcompatibilityenable']?$arrmodulesldap['varmodulesldapmsadcompatibilityenable']:'Disable'); if ($arrmodulesldap['varmodulesldapmsadcompatibilityenable'] == 'Disable') { $varmodulesldapmsadcompatibility = '### MS Active Directory Compatibility is disabled ###'; } else { $varmodulesldapmsadcompatibility = 'chase_referrals = yes' . "\n\trebind = yes"; } // Miscellaneous Configuration + MS Active Directory Compatibility ldap2 $varmodulesldap2msadcompatibilityenable = ($arrmodulesldap['varmodulesldap2msadcompatibilityenable']?$arrmodulesldap['varmodulesldap2msadcompatibilityenable']:'Disable'); if ($arrmodulesldap['varmodulesldap2msadcompatibilityenable'] == 'Disable') { $varmodulesldap2msadcompatibility = '### MS Active Directory Compatibility is disabled ###'; } else { $varmodulesldap2msadcompatibility = 'chase_referrals = yes' . "\n\trebind = yes"; } // When disabled we put this in the file but commented (#) like in the default installation ldap1 if (!$arrmodulesldap['varmodulesldapdmiscenable']) { $varmodulesldapdefaultprofile = '### default_profile = "cn=radprofile,ou=dialup,o=My Org,c=UA" ###'; $varmodulesldapprofileattribute = '### profile_attribute = "radiusProfileDn" ###'; $varmodulesldapaccessattr = '### access_attr = "dialupAccess" ###'; } // When enabled we put in the default values so there is no empty entry if there is not input from GUI else { $varmodulesldapdefaultprofile = ($arrmodulesldap['varmodulesldapdefaultprofile']?$arrmodulesldap['varmodulesldapdefaultprofile']:'cn=radprofile,ou=dialup,o=My Org,c=UA'); $varmodulesldapdefaultprofile = "default_profile = " . '"' . "$varmodulesldapdefaultprofile" . '"'; $varmodulesldapprofileattribute = ($arrmodulesldap['varmodulesldapprofileattribute']?$arrmodulesldap['varmodulesldapprofileattribute']:'radiusProfileDn'); $varmodulesldapprofileattribute = "profile_attribute = " . '"' . "$varmodulesldapprofileattribute" . '"'; $varmodulesldapaccessattr = ($arrmodulesldap['varmodulesldapaccessattr']?$arrmodulesldap['varmodulesldapaccessattr']:'dialupAccess'); $varmodulesldapaccessattr = "access_attr = " . '"' . "$varmodulesldapaccessattr" . '"'; } // When disabled we put this in the file but commented (#) like in the default installation ldap2 if (!$arrmodulesldap['varmodulesldap2dmiscenable']) { $varmodulesldap2defaultprofile = '### default_profile = "cn=radprofile,ou=dialup,o=My Org,c=UA" ###'; $varmodulesldap2profileattribute = '### profile_attribute = "radiusProfileDn" ###'; $varmodulesldap2accessattr = '### access_attr = "dialupAccess" ###'; } // When enabled we put in the default values so there is no empty entry if there is not input from GUI else { $varmodulesldap2defaultprofile = ($arrmodulesldap['varmodulesldap2defaultprofile']?$arrmodulesldap['varmodulesldap2defaultprofile']:'cn=radprofile,ou=dialup,o=My Org,c=UA'); $varmodulesldap2defaultprofile = "default_profile = " . '"' . "$varmodulesldap2defaultprofile" . '"'; $varmodulesldap2profileattribute = ($arrmodulesldap['varmodulesldap2profileattribute']?$arrmodulesldap['varmodulesldap2profileattribute']:'radiusProfileDn'); $varmodulesldap2profileattribute = "profile_attribute = " . '"' . "$varmodulesldap2profileattribute" . '"'; $varmodulesldap2accessattr = ($arrmodulesldap['varmodulesldap2accessattr']?$arrmodulesldap['varmodulesldap2accessattr']:'dialupAccess'); $varmodulesldap2accessattr = "access_attr = " . '"' . "$varmodulesldap2accessattr" . '"'; } // Group membership checking // When disabled we put this in the file but commented (#) like in the default installation ldap1 if (!$arrmodulesldap['varmodulesldapgroupenable']) { $varmodulesldapgroupnameattribute = '### groupname_attribute = cn ###'; $varmodulesldapgroupmembershipfilter = '### groupmembership_filter = "(|(&(objectClass=GroupOfNames)(member=%{control:Ldap-UserDn}))(&(objectClass=GroupOfUniqueNames)(uniquemember=%{control:Ldap-UserDn})))" ###'; $varmodulesldapgroupmembershipattribute = '### groupmembership_attribute = radiusGroupName ###'; $varmodulesldapcomparecheckitems = '### compare_check_items = yes ###'; $varmodulesldapdoxlat = '### do_xlat = yes ###'; $varmodulesldapaccessattrusedforallow = '### access_attr_used_for_allow = yes ###'; } // When enabled we put in the default values so there is no empty entry if there is not input from GUI else { $varmodulesldapgroupnameattribute = ($arrmodulesldap['varmodulesldapgroupnameattribute']?$arrmodulesldap['varmodulesldapgroupnameattribute']:'cn'); $varmodulesldapgroupnameattribute = "groupname_attribute = $varmodulesldapgroupnameattribute"; $varmodulesldapgroupmembershipfilter = ($arrmodulesldap['varmodulesldapgroupmembershipfilter']?$arrmodulesldap['varmodulesldapgroupmembershipfilter']:'(|(&(objectClass=GroupOfNames)(member=%{control:Ldap-UserDn}))(&(objectClass=GroupOfUniqueNames)(uniquemember=%{control:Ldap-UserDn})))'); $varmodulesldapgroupmembershipfilter = "groupmembership_filter = " . '"' . "$varmodulesldapgroupmembershipfilter" . '"'; $varmodulesldapgroupmembershipattribute = ($arrmodulesldap['varmodulesldapgroupmembershipattribute']?$arrmodulesldap['varmodulesldapgroupmembershipattribute']:'radiusGroupName'); $varmodulesldapgroupmembershipattribute = "groupmembership_attribute = $varmodulesldapgroupmembershipattribute"; $varmodulesldapcomparecheckitems = ($arrmodulesldap['varmodulesldapcomparecheckitems']?$arrmodulesldap['varmodulesldapcomparecheckitems']:'yes'); $varmodulesldapcomparecheckitems = "compare_check_items = $varmodulesldapcomparecheckitems"; $varmodulesldapdoxlat = ($arrmodulesldap['varmodulesldapdoxlat']?$arrmodulesldap['varmodulesldapdoxlat']:'yes'); $varmodulesldapdoxlat = "do_xlat = $varmodulesldapdoxlat"; $varmodulesldapaccessattrusedforallow = ($arrmodulesldap['varmodulesldapaccessattrusedforallow']?$arrmodulesldap['varmodulesldapaccessattrusedforallow']:'yes'); $varmodulesldapaccessattrusedforallow = "access_attr_used_for_allow = $varmodulesldapaccessattrusedforallow"; } // Group membership checking // When disabled we put this in the file but commented (#) like in the default installation ldap2 if (!$arrmodulesldap['varmodulesldap2groupenable']) { $varmodulesldap2groupnameattribute = '### groupname_attribute = cn ###'; $varmodulesldap2groupmembershipfilter = '### groupmembership_filter = "(|(&(objectClass=GroupOfNames)(member=%{control:Ldap-UserDn}))(&(objectClass=GroupOfUniqueNames)(uniquemember=%{control:Ldap-UserDn})))" ###'; $varmodulesldap2groupmembershipattribute = '### groupmembership_attribute = radiusGroupName ###'; $varmodulesldap2comparecheckitems = '### compare_check_items = yes ###'; $varmodulesldap2doxlat = '### do_xlat = yes ###'; $varmodulesldap2accessattrusedforallow = '### access_attr_used_for_allow = yes ###'; } // When enabled we put in the default values so there is no empty entry if there is not input from GUI else { $varmodulesldap2groupnameattribute = ($arrmodulesldap['varmodulesldap2groupnameattribute']?$arrmodulesldap['varmodulesldap2groupnameattribute']:'cn'); $varmodulesldap2groupnameattribute = "groupname_attribute = $varmodulesldap2groupnameattribute"; $varmodulesldap2groupmembershipfilter = ($arrmodulesldap['varmodulesldap2groupmembershipfilter']?$arrmodulesldap['varmodulesldap2groupmembershipfilter']:'(|(&(objectClass=GroupOfNames)(member=%{control:Ldap-UserDn}))(&(objectClass=GroupOfUniqueNames)(uniquemember=%{control:Ldap-UserDn})))'); $varmodulesldap2groupmembershipfilter = "groupmembership_filter = " . '"' . "$varmodulesldap2groupmembershipfilter" . '"'; $varmodulesldap2groupmembershipattribute = ($arrmodulesldap['varmodulesldap2groupmembershipattribute']?$arrmodulesldap['varmodulesldap2groupmembershipattribute']:'radiusGroupName'); $varmodulesldap2groupmembershipattribute = "groupmembership_attribute = $varmodulesldap2groupmembershipattribute"; $varmodulesldap2comparecheckitems = ($arrmodulesldap['varmodulesldap2comparecheckitems']?$arrmodulesldap['varmodulesldap2comparecheckitems']:'yes'); $varmodulesldap2comparecheckitems = "compare_check_items = $varmodulesldap2comparecheckitems"; $varmodulesldap2doxlat = ($arrmodulesldap['varmodulesldap2doxlat']?$arrmodulesldap['varmodulesldap2doxlat']:'yes'); $varmodulesldap2doxlat = "do_xlat = $varmodulesldap2doxlat"; $varmodulesldap2accessattrusedforallow = ($arrmodulesldap['varmodulesldap2accessattrusedforallow']?$arrmodulesldap['varmodulesldap2accessattrusedforallow']:'yes'); $varmodulesldap2accessattrusedforallow = "access_attr_used_for_allow = $varmodulesldap2accessattrusedforallow"; } // Keepalive variables ldap1 $varmodulesldapkeepaliveidle = ($arrmodulesldap['varmodulesldapkeepaliveidle']?$arrmodulesldap['varmodulesldapkeepaliveidle']:'60'); $varmodulesldapkeepaliveprobes = ($arrmodulesldap['varmodulesldapkeepaliveprobes']?$arrmodulesldap['varmodulesldapkeepaliveprobes']:'3'); $varmodulesldapkeepaliveinterval = ($arrmodulesldap['varmodulesldapkeepaliveinterval']?$arrmodulesldap['varmodulesldapkeepaliveinterval']:'3'); // Keepalive variables ldap2 $varmodulesldap2keepaliveidle = ($arrmodulesldap['varmodulesldap2keepaliveidle']?$arrmodulesldap['varmodulesldap2keepaliveidle']:'60'); $varmodulesldap2keepaliveprobes = ($arrmodulesldap['varmodulesldap2keepaliveprobes']?$arrmodulesldap['varmodulesldap2keepaliveprobes']:'3'); $varmodulesldap2keepaliveinterval = ($arrmodulesldap['varmodulesldap2keepaliveinterval']?$arrmodulesldap['varmodulesldap2keepaliveinterval']:'3'); $raddb = FREERADIUS_BASE . '/etc/raddb'; $conf .= <<<EOD # -*- text -*- # # $Id$ # Lightweight Directory Access Protocol (LDAP) # # This module definition allows you to use LDAP for # authorization and authentication. # # See raddb/sites-available/default for reference to the # ldap module in the authorize and authenticate sections. # # However, LDAP can be used for authentication ONLY when the # Access-Request packet contains a clear-text User-Password # attribute. LDAP authentication will NOT work for any other # authentication method. # # This means that LDAP servers don't understand EAP. If you # force "Auth-Type = LDAP", and then send the server a # request containing EAP authentication, then authentication # WILL NOT WORK. # # The solution is to use the default configuration, which does # work. # # Setting "Auth-Type = LDAP" is ALMOST ALWAYS WRONG. We # really can't emphasize this enough. # ldap { # # Note that this needs to match the name in the LDAP # server certificate, if you're using ldaps. server = "$varmodulesldapserver" identity = "$varmodulesldapidentity" password = $varmodulesldappassword basedn = "$varmodulesldapbasedn" filter = "$varmodulesldapfilter" base_filter = "$varmodulesldapbasefilter" # How many connections to keep open to the LDAP server. # This saves time over opening a new LDAP socket for # every authentication request. ldap_connections_number = $varmodulesldapldapconnectionsnumber # seconds to wait for LDAP query to finish. default: 20 timeout = $varmodulesldaptimeout # seconds LDAP server has to process the query (server-side # time limit). default: 20 # # LDAP_OPT_TIMELIMIT is set to this value. timelimit = $varmodulesldaptimelimit # # seconds to wait for response of the server. (network # failures) default: 10 # # LDAP_OPT_NETWORK_TIMEOUT is set to this value. net_timeout = $varmodulesldapnettimeout # # This subsection configures the tls related items # that control how FreeRADIUS connects to an LDAP # server. It contains all of the "tls_*" configuration # entries used in older versions of FreeRADIUS. Those # configuration entries can still be used, but we recommend # using these. # tls { # Set this to 'yes' to use TLS encrypted connections # to the LDAP database by using the StartTLS extended # operation. # # The StartTLS operation is supposed to be # used with normal ldap connections instead of # using ldaps (port 689) connections start_tls = $varmodulesldapstarttls cacertfile = {$raddb}/certs/ca_ldap1_cert.pem cacertdir = {$raddb}/certs/ certfile = {$raddb}/certs/radius_ldap1_cert.crt keyfile = {$raddb}/certs/radius_ldap1_cert.key randfile = {$raddb}/certs/random # Certificate Verification requirements. Can be: # "never" (don't even bother trying) # "allow" (try, but don't fail if the cerificate # can't be verified) # "demand" (fail if the certificate doesn't verify.) # # The default is "allow" require_cert = "$varmodulesldaprequirecert" } $varmodulesldapdefaultprofile $varmodulesldapprofileattribute $varmodulesldapaccessattr # Mapping of RADIUS dictionary attributes to LDAP # directory attributes. dictionary_mapping = \${confdir}/ldap.attrmap ################## THE BELOW IS NOT COMPILED WITH FREERADIUS ################################# # Set password_attribute = nspmPassword to get the # user's password from a Novell eDirectory # backend. This will work ONLY IF FreeRADIUS has been # built with the --with-edir configure option. # # See also the following links: # # http://www.novell.com/coolsolutions/appnote/16745.html # https://secure-support.novell.com/KanisaPlatform/Publishing/558/3009668_f.SAL_Public.html # # Novell may require TLS encrypted sessions before returning # the user's password. # # password_attribute = userPassword # Un-comment the following to disable Novell # eDirectory account policy check and intruder # detection. This will work *only if* FreeRADIUS is # configured to build with --with-edir option. # edir_account_policy_check = no ################## THE ABOVE IS NOT COMPILED WITH FREERADIUS ################################# # # Group membership checking. Disabled by default. # $varmodulesldapgroupnameattribute $varmodulesldapgroupmembershipfilter $varmodulesldapgroupmembershipattribute $varmodulesldapcomparecheckitems $varmodulesldapdoxlat $varmodulesldapaccessattrusedforallow # # The following two configuration items are for Active Directory # compatibility. If you see the helpful "operations error" # being returned to the LDAP module, uncomment the next # two lines. # $varmodulesldapmsadcompatibility # # By default, if the packet contains a User-Password, # and no other module is configured to handle the # authentication, the LDAP module sets itself to do # LDAP bind for authentication. # # THIS WILL ONLY WORK FOR PAP AUTHENTICATION. # # THIS WILL NOT WORK FOR CHAP, MS-CHAP, or 802.1x (EAP). # # You can disable this behavior by setting the following # configuration entry to "no". # # allowed values: {no, yes} # set_auth_type = yes # ldap_debug: debug flag for LDAP SDK # (see OpenLDAP documentation). Set this to enable # huge amounts of LDAP debugging on the screen. # You should only use this if you are an LDAP expert. # # default: 0x0000 (no debugging messages) # Example:(LDAP_DEBUG_FILTER+LDAP_DEBUG_CONNS) #ldap_debug = 0x0028 # # Keepalive configuration. This MAY NOT be supported by your # LDAP library. If these configuration entries appear in the # output of "radiusd -X", then they are supported. Otherwise, # they are unsupported, and changing them will do nothing. # keepalive { # LDAP_OPT_X_KEEPALIVE_IDLE idle = $varmodulesldapkeepaliveidle # LDAP_OPT_X_KEEPALIVE_PROBES probes = $varmodulesldapkeepaliveprobes # LDAP_OPT_X_KEEPALIVE_INTERVAL interval = $varmodulesldapkeepaliveinterval } } ldap ldap2{ # # Note that this needs to match the name in the LDAP # server certificate, if you're using ldaps. server = "$varmodulesldap2server" identity = "$varmodulesldap2identity" password = $varmodulesldap2password basedn = "$varmodulesldap2basedn" filter = "$varmodulesldap2filter" base_filter = "$varmodulesldap2basefilter" # How many connections to keep open to the LDAP server. # This saves time over opening a new LDAP socket for # every authentication request. ldap_connections_number = $varmodulesldap2ldapconnectionsnumber # seconds to wait for LDAP query to finish. default: 20 timeout = $varmodulesldap2timeout # seconds LDAP server has to process the query (server-side # time limit). default: 20 # # LDAP_OPT_TIMELIMIT is set to this value. timelimit = $varmodulesldap2timelimit # # seconds to wait for response of the server. (network # failures) default: 10 # # LDAP_OPT_NETWORK_TIMEOUT is set to this value. net_timeout = $varmodulesldap2nettimeout # # This subsection configures the tls related items # that control how FreeRADIUS connects to an LDAP # server. It contains all of the "tls_*" configuration # entries used in older versions of FreeRADIUS. Those # configuration entries can still be used, but we recommend # using these. # tls { # Set this to 'yes' to use TLS encrypted connections # to the LDAP database by using the StartTLS extended # operation. # # The StartTLS operation is supposed to be # used with normal ldap connections instead of # using ldaps (port 689) connections start_tls = $varmodulesldap2starttls cacertfile = {$raddb}/certs/ca_ldap2_cert.pem cacertdir = {$raddb}/certs/ certfile = {$raddb}/certs/radius_ldap2_cert.crt keyfile = {$raddb}/certs/radius_ldap2_cert.key randfile = {$raddb}/certs/random # Certificate Verification requirements. Can be: # "never" (don't even bother trying) # "allow" (try, but don't fail if the cerificate # can't be verified) # "demand" (fail if the certificate doesn't verify.) # # The default is "allow" require_cert = "$varmodulesldap2requirecert" } $varmodulesldap2defaultprofile $varmodulesldap2profileattribute $varmodulesldap2accessattr # Mapping of RADIUS dictionary attributes to LDAP # directory attributes. dictionary_mapping = \${confdir}/ldap.attrmap ################## THE BELOW IS NOT COMPILED WITH FREERADIUS ################################# # Set password_attribute = nspmPassword to get the # user's password from a Novell eDirectory # backend. This will work ONLY IF FreeRADIUS has been # built with the --with-edir configure option. # # See also the following links: # # http://www.novell.com/coolsolutions/appnote/16745.html # https://secure-support.novell.com/KanisaPlatform/Publishing/558/3009668_f.SAL_Public.html # # Novell may require TLS encrypted sessions before returning # the user's password. # # password_attribute = userPassword # Un-comment the following to disable Novell # eDirectory account policy check and intruder # detection. This will work *only if* FreeRADIUS is # configured to build with --with-edir option. # edir_account_policy_check = no ################## THE ABOVE IS NOT COMPILED WITH FREERADIUS ################################# # # Group membership checking. Disabled by default. # $varmodulesldap2groupnameattribute $varmodulesldap2groupmembershipfilter $varmodulesldap2groupmembershipattribute $varmodulesldap2comparecheckitems $varmodulesldap2doxlat $varmodulesldap2accessattrusedforallow # # The following two configuration items are for Active Directory # compatibility. If you see the helpful "operations error" # being returned to the LDAP module, uncomment the next # two lines. # $varmodulesldap2msadcompatibility # # By default, if the packet contains a User-Password, # and no other module is configured to handle the # authentication, the LDAP module sets itself to do # LDAP bind for authentication. # # THIS WILL ONLY WORK FOR PAP AUTHENTICATION. # # THIS WILL NOT WORK FOR CHAP, MS-CHAP, or 802.1x (EAP). # # You can disable this behavior by setting the following # configuration entry to "no". # # allowed values: {no, yes} # set_auth_type = yes # ldap_debug: debug flag for LDAP SDK # (see OpenLDAP documentation). Set this to enable # huge amounts of LDAP debugging on the screen. # You should only use this if you are an LDAP expert. # # default: 0x0000 (no debugging messages) # Example:(LDAP_DEBUG_FILTER+LDAP_DEBUG_CONNS) #ldap_debug = 0x0028 # # Keepalive configuration. This MAY NOT be supported by your # LDAP library. If these configuration entries appear in the # output of "radiusd -X", then they are supported. Otherwise, # they are unsupported, and changing them will do nothing. # keepalive { # LDAP_OPT_X_KEEPALIVE_IDLE idle = $varmodulesldap2keepaliveidle # LDAP_OPT_X_KEEPALIVE_PROBES probes = $varmodulesldap2keepaliveprobes # LDAP_OPT_X_KEEPALIVE_INTERVAL interval = $varmodulesldap2keepaliveinterval } } EOD; $filename = FREERADIUS_BASE . '/etc/raddb/modules/ldap'; conf_mount_rw(); file_put_contents($filename, $conf); chmod($filename, 0640); conf_mount_ro(); // We need to rebuild "freeradius_serverdefault_resync" before restart service // "freeradius_serverdefault_resync" needs to restart other dependencies so we are pointing directly to "freeradius_settings_resync()" freeradius_serverdefault_resync(); restart_service("radiusd"); } function freeradius_plainmacauth_resync() { global $config; $conf = ''; // Variables: If not using 802.1x, mac address must be known $varsettings = $config['installedpackages']['freeradiussettings']['config'][0]; // defining variables with filename path $filepolicyconf = FREERADIUS_BASE . '/etc/raddb/policy.conf'; $filepolicyconfbackup = FREERADIUS_BASE . '/etc/raddb/policy.conf.backup'; $filemodulesfiles = FREERADIUS_BASE . '/etc/raddb/modules/files'; $filemodulesfilesbackup = FREERADIUS_BASE . '/etc/raddb/files.backup'; // If unchecked then plain mac auth is disabled and backups of the original files will be restored if ($varsettings['varsettingsenablemacauth'] == '') { // This is a check - only restore files if they aren't already if (file_exists(FREERADIUS_BASE . "/etc/raddb/plain_macauth_enabled")) { log_error("FreeRADIUS: Plain-MAC-Auth disabled. Restoring the original file from {$filepolicyconfbackup} and {$filemodulesfilesbackup}"); copy($filepolicyconfbackup, $filepolicyconf); copy($filemodulesfilesbackup, $filemodulesfiles); unlink(FREERADIUS_BASE . "/etc/raddb/plain_macauth_enabled"); freeradius_serverdefault_resync(); } } // If checked then plain mac auth is enabled else { // This is a check - only modify files if they aren't already if (!file_exists(FREERADIUS_BASE . "/etc/raddb/plain_macauth_enabled")) { freeradius_modulesfiles_resync(); freeradius_policyconf_resync(); exec("cd " . FREERADIUS_BASE . "/etc/raddb && touch " . FREERADIUS_BASE . "/etc/raddb/plain_macauth_enabled"); log_error("FreeRADIUS: Plain-MAC-Auth enabled. Modified {$filepolicyconf} and {$filemodulesfiles}"); freeradius_serverdefault_resync(); } } } function freeradius_modulesfiles_resync() { global $config; $conf = ''; $conf .= <<<EOD # -*- text -*- # # \$Id\$ # Livingston-style 'users' file # files { # The default key attribute to use for matches. The content # of this attribute is used to match the "name" of the # entry. #key = "%{Stripped-User-Name:-%{User-Name}}" usersfile = \${confdir}/users acctusersfile = \${confdir}/acct_users preproxy_usersfile = \${confdir}/preproxy_users # If you want to use the old Cistron 'users' file # with FreeRADIUS, you should change the next line # to 'compat = cistron'. You can the copy your 'users' # file from Cistron. compat = no } # An example which defines a second instance of the "files" module. # This instance is named "second_files". In order for it to be used # in a virtual server, it needs to be listed as "second_files" # inside of the "authorize" section (or other section). If you just # list "files", that will refer to the configuration defined above. # # The two names here mean: # "files" - this is a configuration for the "rlm_files" module # "second_files" - this is a named configuration, which isn't # the default configuration. files authorized_macs { # The default key attribute to use for matches. The content # of this attribute is used to match the "name" of the # entry. key = "%{Calling-Station-ID}" usersfile = \${confdir}/authorized_macs # If you want to use the old Cistron 'users' file # with FreeRADIUS, you should change the next line # to 'compat = cistron'. You can the copy your 'users' # file from Cistron. compat = no } EOD; $filename = FREERADIUS_BASE . '/etc/raddb/modules/files'; conf_mount_rw(); file_put_contents($filename, $conf); chmod($filename, 0640); conf_mount_ro(); } function freeradius_policyconf_resync() { global $config; $conf = ''; $conf .= <<<EOD # -*- text -*- ## ## policy.conf -- FreeRADIUS server configuration file. ## ## http://www.freeradius.org/ ## \$Id\$ ## # # Policies are virtual modules, similar to those defined in the # "instantate" section of radiusd.conf. # # Defining a policy here means that it can be referenced in multiple # places as a *name*, rather than as a series of conditions to match, # and actions to take. # # Policies are something like subroutines in a normal language, but # they cannot be called recursively. They MUST be defined in order. # If policy A calls policy B, then B MUST be defined before A. # policy { # # Forbid all EAP types. # forbid_eap { if (EAP-Message) { reject } } # # Forbid all non-EAP types outside of an EAP tunnel. # permit_only_eap { if (!EAP-Message) { # We MAY be inside of a TTLS tunnel. # PEAP and EAP-FAST require EAP inside of # the tunnel, so this check is OK. # If so, then there MUST be an outer EAP message. if (!"%{outer.request:EAP-Message}") { reject } } } # # Forbid all attempts to login via realms. # deny_realms { if (User-Name =~ /@|\\\\/) { reject } } # # If you want the server to pretend that it is dead, # then use the "do_not_respond" policy. # do_not_respond { update control { Response-Packet-Type := Do-Not-Respond } handled } # # Force some sanity on User-Name. This helps to avoid issues # issues where the back-end database is "forgiving" about # what constitutes a user name. # filter_username { # spaces at the start: reject if (User-Name =~ /^ /) { reject } # spaces at the end: reject if (User-Name =~ / \$\$/) { reject } # Mixed case: reject if (User-Name != "%{tolower:%{User-Name}}") { reject } } # # The following policies are for the Chargeable-User-Identity # (CUI) configuration. # # # The client indicates it can do CUI by sending a CUI attribute # containing one zero byte # cui_authorize { update request { Chargeable-User-Identity:='\\\\000' } } # # Add a CUI attribute based on the User-Name, and a secret key # known only to this server. # cui_postauth { if (FreeRadius-Proxied-To == 127.0.0.1) { if (outer.request:Chargeable-User-Identity) { update outer.reply { Chargeable-User-Identity:="%{md5:%{config:cui_hash_key}%{User-Name}}" } } } else { if (Chargeable-User-Identity) { update reply { Chargeable-User-Identity="%{md5:%{config:cui_hash_key}%{User-Name}}" } } } } # # If there is a CUI attribute in the reply, add it to the DB. # cui_updatedb { if (reply:Chargeable-User-Identity) { cui } } # # If we had stored a CUI for the User, add it to the request. # cui_accounting { # # If the CUI isn't in the packet, see if we can find it # in the DB. # if (!Chargeable-User-Identity) { update control { Chargable-User-Identity := "%{cui: SELECT cui FROM cui WHERE clientipaddress = '%{Client-IP-Address}' AND callingstationid = '%{Calling-Station-Id}' AND username = '%{User-Name}'}" } } # # If it exists now, then write out when we last saw # this CUI. # if (Chargeable-User-Identity && (Chargeable-User-Identity != "")) { cui } } # # Normalize the MAC Addresses in the Calling/Called-Station-Id # mac-addr = ([0-9a-f]{2})[^0-9a-f]?([0-9a-f]{2})[^0-9a-f]?([0-9a-f]{2})[^0-9a-f]?([0-9a-f]{2})[^0-9a-f]?([0-9a-f]{2})[^0-9a-f]?([0-9a-f]{2}) # Add "rewrite.called_station_id" in the "authorize" and "preacct" # sections. rewrite.called_station_id { if((Called-Station-Id) && "%{Called-Station-Id}" =~ /^%{config:policy.mac-addr}(:(.+))?\$/i) { update request { Called-Station-Id := "%{tolower:%{1}-%{2}-%{3}-%{4}-%{5}-%{6}}" } # SSID component? if ("%{8}") { update request { Called-Station-Id := "%{Called-Station-Id}:%{8}" } } updated } else { noop } } # Add "rewrite.calling_station_id" in the "authorize" and "preacct" # sections. #rewrite.calling_station_id { # if((Calling-Station-Id) && "%{Calling-Station-Id}" =~ /^%{config:policy.mac-addr}\$/i) { # update request { # Calling-Station-Id := "%{tolower:%{1}-%{2}-%{3}-%{4}-%{5}-%{6}}" # } # updated # } # else { # noop # } #} ##### MODIFIED FOR http://wiki.freeradius.org/Mac-Auth#Mac-Auth+or+802.1x ##### # Add "rewrite_calling_station_id" in the "authorize" and "preacct" # sections. rewrite_calling_station_id { if (Calling-Station-Id =~ /([0-9a-f]{2})[-:]?([0-9a-f]{2})[-:]?([0-9a-f]{2})[-:]?([0-9a-f]{2})[-:]?([0-9a-f]{2})[-:]?([0-9a-f]{2})/i){ update request { Calling-Station-Id := "%{tolower:%{1}-%{2}-%{3}-%{4}-%{5}-%{6}}" } } else { noop } } } EOD; $filename = FREERADIUS_BASE . '/etc/raddb/policy.conf'; conf_mount_rw(); file_put_contents($filename, $conf); chmod($filename, 0640); conf_mount_ro(); } function freeradius_motp_resync() { global $config; $conf = ''; $varsettings = $config['installedpackages']['freeradiussettings']['config'][0]; $varsettingsmotptimespan = ($varsettings['varsettingsmotptimespan']?$varsettings['varsettingsmotptimespan']:'2'); $varsettingsmotptimespanbeforeafter = $varsettingsmotptimespan + $varsettingsmotptimespan; $varsettingsmotpdeleteoldpasswords = $varsettingsmotptimespanbeforeafter + 1; $varsettingsmotppasswordattempts = ($varsettings['varsettingsmotppasswordattempts']?$varsettings['varsettingsmotppasswordattempts']:'5'); $varsettingsmotpchecksumtype = ($varsettings['varsettingsmotpchecksumtype']?$varsettings['varsettingsmotpchecksumtype']:'md5'); $varsettingsmotptokenlength = ($varsettings['varsettingsmotptokenlength']?$varsettings['varsettingsmotptokenlength']:'1-6'); // check if disabled then we delete bash und otpverify.sh script if ($varsettings['varsettingsmotpenable'] == '') { if (file_exists(FREERADIUS_BASE . "/etc/raddb/scripts/otpverify.sh")) { unlink(FREERADIUS_BASE . "/etc/raddb/scripts/otpverify.sh"); } if (exec("cd /var/db/pkg && ls | grep bash") == "bash-4.1.7") { exec("cd /var/db/pkg && pkg_delete `ls | grep bash`"); log_error('FreeRADIUS: Uninstalling package "bash-4.1.7" which comes with Mobile-One-Time-Password (motp).'); } if (exec("cd /var/db/pkg && ls | grep bash") == "bash-4.2.20") { exec("cd /var/db/pkg && pkg_delete `ls | grep bash`"); log_error('FreeRADIUS: Uninstalling package "bash-4.2.20" which comes with Mobile-One-Time-Password (motp).'); } } // check if enabled then we need to download "bash" else { if (substr(trim(file_get_contents("/etc/version")),0,3) == "2.0") { if (exec("cd /var/db/pkg && ls | grep bash") != "bash-4.1.7") { log_error('FreeRADIUS: Downloading and installing package "bash-4.1.7" to use Mobile-One-Time-Password (motp).'); exec("pkg_add -r http://ftp-archive.freebsd.org/pub/FreeBSD-Archive/ports/`uname -m`/packages-8.1-release/All/bash-4.1.7.tbz"); } } else { if (exec("cd /var/db/pkg && ls | grep bash") != "bash-4.2.20") { log_error('FreeRADIUS: Downloading and installing package "bash-4.2.20" to use Mobile-One-Time-Password (motp).'); exec("pkg_add -r http://ftp-archive.freebsd.org/pub/FreeBSD/ports/`uname -m`/packages-8.3-release/All/bash-4.2.20.tbz"); } } $conf .= <<<EOD #!/bin/bash # # Mobile One Time Passwords (Mobile-OTP) for Java 2 Micro Edition, J2ME # written by Matthias Straub, Heilbronn, Germany, 2003 # (c) 2003 by Matthias Straub # Modified 2012 by Alexander Wilke <nachtfalkeaw@web.de> # # Version 1.05a # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU Library General Public # License as published by the Free Software Foundation; either # version 2 of the License, or (at your option) any later version. # # This software is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Library General Public License for more details. # # arguments: \$1 \$2 \$3 \$4 \$5 # \$1 - username # \$2 - one-time-password that is to be checked # \$3 - init-secred from token (to init token: #**#) # \$4 - user PIN # \$5 - time difference between token and server in 10s of seconds (360 = 1 hour) # # one-time-password must match md5(EPOCHTIME+SECRET+PIN) # # # otpverify.sh version 1.04b, Feb. 2003 # otpverify.sh version 1.04c, Nov. 2008 # changed line 1 to ksh because of problems with todays bash an sh # otpverify.sh version 1.05a, Jan. 2011 # changed back to bash and added in shopts line to ensure aliases handled # correctly (bash is always available on any modern *nix unlike ksh) # PATH=\$PATH:/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin alias checksum=$varsettingsmotpchecksumtype have_md5="true" # ensure aliases are expanded by bash shopt -s expand_aliases function chop { num=`echo -n "\$1" | wc -c | sed 's/ //g' ` nummin1=`expr \$num "-" 1` echo -n "\$1" | cut -b 1-\$nummin1 } if [ ! \$# -eq 5 ] ; then echo "USAGE: otpverify.sh Username, OTP, Init-Secret, PIN, Offset" logger -f /var/log/system.log "FreeRADIUS: Mobile-One-Time-Password - wrong syntax - USAGE: otpverify.sh Username, OTP, Init-Secret, PIN, Offset"; exit 14 fi mkdir /var/log/motp 2>/dev/null mkdir /var/log/motp/cache 2>/dev/null mkdir /var/log/motp/users 2>/dev/null chmod og-rxw /var/log/motp 2>/dev/null || { echo "FAIL! Need write-access to /var/log/motp";logger -f /var/log/system.log "FreeRADIUS: Mobile-One-Time-Password - need write-access to /var/log/motp"; exit 17; } chmod og-rxw /var/log/motp/cache chmod og-rxw /var/log/motp/users USERNAME=`echo -n "\$1" | sed 's/[^0-9a-zA-Z._-]/X/g' ` PASSWD=`echo -n "\$2" | sed 's/[^0-9a-f]/0/g' ` SECRET=`echo -n "\$3" | sed 's/[^0-9a-f]/0/g' ` PIN=`echo -n "\$4" | sed 's/[^0-9]/0/g' ` OFFSET=`echo -n "\$5" | sed 's/[^0-9]/0/g' ` EPOCHTIME=`date +%s` ; EPOCHTIME=`chop \$EPOCHTIME` # delete old logins find /var/log/motp/cache -type f -cmin +$varsettingsmotpdeleteoldpasswords | xargs rm 2>/dev/null if [ -e "/var/log/motp/cache/\$PASSWD" ]; then echo "FAIL" logger -f /var/log/system.log "FreeRADIUS: Authentication failed! Mobile-One-Time-Password \$PASSWD is already used!" exit 15 fi # account locked? if [ "`cat /var/log/motp/users/\$USERNAME 2>/dev/null`" == "$varsettingsmotppasswordattempts" ]; then echo "FAIL" logger -f /var/log/system.log "FreeRADIUS: Authentication failed! Too many wrong password attempts. User is locked! To unlock delete /var/log/motp/users/\$USERNAME" exit 13 fi I=0 EPOCHTIME=`expr \$EPOCHTIME - $varsettingsmotptimespan` EPOCHTIME=`expr \$EPOCHTIME + \$OFFSET` while [ \$I -lt $varsettingsmotptimespanbeforeafter ] ; do # `$varsettingsmotptimespan * 10` seconds before and after OTP=`printf \$EPOCHTIME\$SECRET\$PIN|checksum|cut -b $varsettingsmotptokenlength` if [ "\$OTP" = "\$PASSWD" ] ; then touch /var/log/motp/cache/\$OTP || { echo "FAIL! Need write-access to /var/log/motp";logger -f /var/log/system.log "FreeRADIUS: Mobile-One-Time-Password - need write-access to /var/log/motp/cache"; exit 17; } echo "ACCEPT" logger -f /var/log/system.log "FreeRADIUS: Authentication success! Mobile-One-Time-Password \$PASSWD for user \$USERNAME is correct!" rm "/var/log/motp/users/\$USERNAME" 2>/dev/null exit 0 fi I=`expr \$I + 1` EPOCHTIME=`expr \$EPOCHTIME + 1` done echo "FAIL" NUMFAILS=`cat "/var/log/motp/users/\$USERNAME" 2>/dev/null` if [ "\$NUMFAILS" = "" ]; then NUMFAILS=0 fi NUMFAILS=`expr \$NUMFAILS + 1` echo \$NUMFAILS > "/var/log/motp/users/\$USERNAME" NUMFAILSLEFT=`expr $varsettingsmotppasswordattempts - \$NUMFAILS` logger -f /var/log/system.log "FreeRADIUS: Authentication failed! Mobile-One-Time-Password incorrect. \$NUMFAILSLEFT attempts left. " exit 11 EOD; $filename = FREERADIUS_BASE . '/etc/raddb/scripts/otpverify.sh'; conf_mount_rw(); file_put_contents($filename, $conf); chmod($filename, 0750); conf_mount_ro(); // end of above 'check if enabled then we need to download "bash"' } } function freeradius_modulesmotp_resync() { global $config; $conf = ''; // put the constant to a variable $varFREERADIUS_BASE = FREERADIUS_BASE; $conf .= <<<EOD exec motp { wait = yes program = "/usr/local/bin/bash $varFREERADIUS_BASE/etc/raddb/scripts/otpverify.sh %{request:User-Name} %{request:User-Password} %{reply:MOTP-Init-Secret} %{reply:MOTP-PIN} %{reply:MOTP-Offset}" } EOD; $filename = FREERADIUS_BASE . '/etc/raddb/modules/motp'; conf_mount_rw(); file_put_contents($filename, $conf); chmod($filename, 0640); conf_mount_ro(); } function freeradius_modulesdatacounter_resync() { global $config; $conf = ''; // put the constant to a variable $varFREERADIUS_BASE = FREERADIUS_BASE; $conf .= <<<EOD exec datacounterdaily { wait = yes program = "/bin/sh $varFREERADIUS_BASE/etc/raddb/scripts/datacounter_acct.sh %{request:User-Name} daily %{request:Acct-Input-Octets} %{request:Acct-Output-Octets}" } exec datacounterweekly { wait = yes program = "/bin/sh $varFREERADIUS_BASE/etc/raddb/scripts/datacounter_acct.sh %{request:User-Name} weekly %{request:Acct-Input-Octets} %{request:Acct-Output-Octets}" } exec datacountermonthly { wait = yes program = "/bin/sh $varFREERADIUS_BASE/etc/raddb/scripts/datacounter_acct.sh %{request:User-Name} monthly %{request:Acct-Input-Octets} %{request:Acct-Output-Octets}" } exec datacounterforever { wait = yes program = "/bin/sh $varFREERADIUS_BASE/etc/raddb/scripts/datacounter_acct.sh %{request:User-Name} forever %{request:Acct-Input-Octets} %{request:Acct-Output-Octets}" } EOD; $filename = FREERADIUS_BASE . '/etc/raddb/modules/datacounter_acct'; conf_mount_rw(); file_put_contents($filename, $conf); chmod($filename, 0640); conf_mount_ro(); } function freeradius_datacounter_auth_resync() { global $config; $conf = ''; $conf .= <<<EOD #!/bin/sh ### USAGE: datacounter_auth.sh USERNAME TIMERANGE ### We need this parameters from freeradius users file and ../raddb/modules/datacounter_acct USERNAME=`echo -n "\\$1" | sed 's/[^0-9a-zA-Z._:-]/X/g' ` TIMERANGE=`echo -n "\\$2" | sed 's/[^a-z]//g' ` ### This is to make sure there is a used-octets file after the cronjob resetted the counter if [ -e "/var/log/radacct/datacounter/\$TIMERANGE/max-octets-\$USERNAME" ] && [ ! -e "/var/log/radacct/datacounter/\$TIMERANGE/used-octets-\$USERNAME" ]; then echo 0 > "/var/log/radacct/datacounter/\$TIMERANGE/used-octets-\$USERNAME" fi ### The next two lines are just for getting values for logging output MAXOCTETSUSERNAMEMB=$((`cat "/var/log/radacct/datacounter/\$TIMERANGE/max-octets-\$USERNAME"`/1024/1024)) USEDOCTETSUSERNAMEMB=$((`cat "/var/log/radacct/datacounter/\$TIMERANGE/used-octets-\$USERNAME"`/1024/1024)) ### We check if MAX-OCTETS-USERNAME is greater than USED-OCTETS-USERNAME and accept or reject the user if [ `cat "/var/log/radacct/datacounter/\$TIMERANGE/max-octets-\$USERNAME"` -gt `cat "/var/log/radacct/datacounter/\$TIMERANGE/used-octets-\$USERNAME"` ]; then logger -f /var/log/system.log "FreeRADIUS: Used amount of \$TIMERANGE traffic by \$USERNAME is \$USEDOCTETSUSERNAMEMB MB of \$MAXOCTETSUSERNAMEMB MB! The user was accepted!!!" exit 0 else logger -f /var/log/system.log "FreeRADIUS: Credentials are probably correct but the user \$USERNAME has reached the \$TIMERANGE Amount of Upload and Download Traffic which is \$USEDOCTETSUSERNAMEMB MB of \$MAXOCTETSUSERNAMEMB MB! The user was rejected!!!" exit 99 fi EOD; $filename = FREERADIUS_BASE . '/etc/raddb/scripts/datacounter_auth.sh'; conf_mount_rw(); file_put_contents($filename, $conf); chmod($filename, 0750); conf_mount_ro(); } function freeradius_datacounter_acct_resync() { global $config; $conf = ''; $conf .= <<<EOD #!/bin/sh ### USAGE: datacounter_acct.sh USERNAME TIMERANGE ACCTINPUTOCTETS ACCTOUTPUTOCTETS ### We need this from an Accounting-Request packet to count the octets USERNAME=`echo -n "\\$1" | sed 's/[^0-9a-zA-Z.:_-]/X/g' ` TIMERANGE=`echo -n "\\$2" | sed 's/[^a-z]//g' ` ACCTINPUTOCTETS=`echo -n "\\$3" | sed 's/[^0-9]/0/g' ` ACCTOUTPUTOCTETS=`echo -n "\\$4" | sed 's/[^0-9]/0/g' ` ### If we do not get Octets we set some default values if [ ! \$ACCTINPUTOCTETS ]; then ACCTINPUTOCTETS=0 fi if [ ! \$ACCTOUTPUTOCTETS ]; then ACCTOUTPUTOCTETS=0 fi ### We only write this to the file if username exists ### If all counters are activated (daily, weekly, monthly, forever) we need to check which is active for the user if [ ! -e "/var/log/radacct/datacounter/\$TIMERANGE/max-octets-\$USERNAME" ]; then exit 0 else ### If no used-octets file exist then we assume that it was deleted by cron job and we need to create a new file starting from zero if [ ! -e "/var/log/radacct/datacounter/\$TIMERANGE/used-octets-\$USERNAME" ]; then echo 0 > "/var/log/radacct/datacounter/\$TIMERANGE/used-octets-\$USERNAME" fi ### The following two lines (chose the one or the other) are a bad workaround to make accounting accurate with stop/start accounting on pfsense 2.0.1 - it only works if the session will not be interrupted (host disconnects) ### USEDOCTETS=\$((\$ACCTINPUTOCTETS+\$ACCTOUTPUTOCTETS)) USEDOCTETS=\$((\$ACCTINPUTOCTETS+\$ACCTOUTPUTOCTETS+`cat "/var/log/radacct/datacounter/\$TIMERANGE/used-octets-\$USERNAME"`)) echo "\$USEDOCTETS" > "/var/log/radacct/datacounter/\$TIMERANGE/used-octets-\$USERNAME" exit 0 fi EOD; $filename = FREERADIUS_BASE . '/etc/raddb/scripts/datacounter_acct.sh'; conf_mount_rw(); file_put_contents($filename, $conf); chmod($filename, 0750); conf_mount_ro(); } function freeradius_dictionary_resync() { global $config; $conf = ''; $conf .= <<<EOD # # This is the master dictionary file, which references the # pre-defined dictionary files included with the server. # # Any new/changed attributes MUST be placed in this file, as # the pre-defined dictionaries SHOULD NOT be edited. # # \$Id\$ # # # The DHCP dictionary is used only when the server is built with # "configure --with-dhcp". It is not (and should not) be used in # other situations. If you are running just a RADIUS server, this # line can be deleted. If you are using DHCP, the following line # should be uncommented. # # Ideally, the "configure" process should automatically enable this # dictionary, but we don't yet do that. # #\$INCLUDE /usr/local/dictionary.dhcp # # The filename given here should be an absolute path. # \$INCLUDE /usr/local/share/freeradius/dictionary # # Place additional attributes or \$INCLUDEs here. They will # over-ride the definitions in the pre-defined dictionaries. # # See the 'man' page for 'dictionary' for information on # the format of the dictionary files. # # If you want to add entries to the dictionary file, # which are NOT going to be placed in a RADIUS packet, # add them here. The numbers you pick should be between # 3000 and 4000. # #ATTRIBUTE My-Local-String 3000 string #ATTRIBUTE My-Local-IPAddr 3001 ipaddr #ATTRIBUTE My-Local-Integer 3002 integer ### Attributes for mobile-One-Time-Password ATTRIBUTE MOTP-Init-Secret 900 string ATTRIBUTE MOTP-PIN 901 string ATTRIBUTE MOTP-Offset 902 string EOD; $filename = FREERADIUS_BASE . '/etc/raddb/dictionary'; conf_mount_rw(); file_put_contents($filename, $conf); chmod($filename, 0640); conf_mount_ro(); } ?>