Skip to content

Instantly share code, notes, and snippets.

@jazzl0ver
Created November 13, 2019 16:04
Show Gist options
  • Save jazzl0ver/d53cb9f55523a8a39ba8c2c0813eb335 to your computer and use it in GitHub Desktop.
Save jazzl0ver/d53cb9f55523a8a39ba8c2c0813eb335 to your computer and use it in GitHub Desktop.
Replace freeradius users in pfSense configuration file with the supplied CSV file
#!/usr/bin/perl
#
# Script takes pfSense configuration file (1st argument), strips out all freeradius users
# and replaces them with the users from the CSV file (2nd argument):
# ./freeradius_users_csv_to_xml.pl pfSense-config.xml users.csv > pfSense-config-new.xml
#
# After the config uploaded and pfSense rebooted, https://gist.github.com/jazzl0ver/b605b1b6fc1effa448fa55467797ac81 patch should be applied:
#
# cd /root; patch -p0 < freeradius.inc.patch
#
# CSV file should use semi-colon as a separator and contain no header line. Example:
# [email protected];http://www.google.com;Feb 12 2020;300;Any;360;forever;5000;1000;1000
#
# The fields are:
# User
# Redirection URL
# Expiration Date
# Session Timeout
# Possible Login Times
# Amount of Time
# Time Period
# Amount of Download and Upload
# Maximum Bandwidth Up
# Maximum Bandwidth Down
# WARNING: The script doesn't validate all the input. It will die just in case supplied username is empty
# or supplied Time Period is not one of Daily, Weekly, Monthly and Forever
#
# CAUTION: the resulting file might be very large, so make sure to tune pfSense's /var/run, /tmp and
# PHP memory_limit (/etc/inc/config.inc) accordingly
#
$start_users_section = 0;
open( PFSENSE_CONF, "<", $ARGV[0] ) || die("\nCannot open the pfsense configuration file $ARGV[0]\n$!");
while( <PFSENSE_CONF> ){
chop;
if (/<freeradius><\/freeradius>/) {
print "<freeradius>", "\n";
$start_users_section = 1;
&csv_to_xml;
$start_users_section = 0;
print "</freeradius>", "\n";
}
else {
if (/<freeradius>$/) {
print "<freeradius>", "\n";
$start_users_section = 1;
&csv_to_xml;
}
if (/<\/freeradius>/) {
$start_users_section = 0;
}
}
if ($start_users_section == 0) {
print $_, "\n";
}
else {
next;
}
}
sub csv_to_xml {
open( CSV_FILE, "<", $ARGV[1] ) || die("\nCannot open the csv configuration file $ARGV[1]\n$!");
$line_count = 0;
# read each line of the configuration line
reading:
while( <CSV_FILE> ){
chop();
chop() if (/\r/);
$line_count++;
# skip comments
next if( /^#/ || /^$/);
my ($user, $url, $expire, $timeout, $login_times, $amount, $period, $quota, $bandup, $banddown) = split(/,/);
if ($user eq "") {
close(CSV_FILE);
die "User name is empty in the 1st column at line $line_count, exiting...";
}
if ( !($period eq "Daily" || $period eq "Weekly" || $period eq "Monthly" || $period eq "Forever") ) {
close(CSV_FILE);
die "Time period field ($period) is not correct at line $line_count. Possible values: Daily, Weekly, Monthly and Forever. Exiting...";
}
print <<EOT;
<config>
<sortable></sortable>
<varusersusername>$user</varusersusername>
<varuserspassword></varuserspassword>
<varuserspasswordencryption>Cleartext-Password</varuserspasswordencryption>
<varusersmotpenable></varusersmotpenable>
<varusersauthmethod>motp</varusersauthmethod>
<varusersmotpinitsecret></varusersmotpinitsecret>
<varusersmotppin></varusersmotppin>
<varusersmotpoffset></varusersmotpoffset>
<qrcodetext></qrcodetext>
<varuserswisprredirectionurl></varuserswisprredirectionurl>
<varuserssimultaneousconnect></varuserssimultaneousconnect>
<description></description>
<varusersframedipaddress></varusersframedipaddress>
<varusersframedipnetmask></varusersframedipnetmask>
<varusersframedroute></varusersframedroute>
<varusersvlanid></varusersvlanid>
<varusersexpiration>$expire</varusersexpiration>
<varuserssessiontimeout>$timeout</varuserssessiontimeout>
<varuserslogintime></varuserslogintime>
<varusersamountoftime>$amount</varusersamountoftime>
<varuserspointoftime>$period</varuserspointoftime>
<varusersmaxtotaloctets>$quota</varusersmaxtotaloctets>
<varusersmaxtotaloctetstimerange>$period</varusersmaxtotaloctetstimerange>
<varusersmaxbandwidthdown>$bandup</varusersmaxbandwidthdown>
<varusersmaxbandwidthup>$banddown</varusersmaxbandwidthup>
<varusersacctinteriminterval></varusersacctinteriminterval>
<varuserstopadditionaloptions></varuserstopadditionaloptions>
<varuserscheckitemsadditionaloptions></varuserscheckitemsadditionaloptions>
<varusersreplyitemsadditionaloptions></varusersreplyitemsadditionaloptions>
</config>
EOT
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment