smradclient 5.74 KB
Newer Older
1
2
#!/usr/bin/perl
# Radius client
3
# Copyright (C) 2007-2016, AllWorldIT
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

use strict;
use warnings;

use lib('/usr/local/lib/smradius-0.0','/usr/lib/smradius-0.0',
Nigel Kukard's avatar
Nigel Kukard committed
23
24
	'/usr/lib64/smradius-0.0','smradius','awitpt');

25

26
27
28
29
30
31
# Check Config::IniFiles is instaslled
if (!eval {require Config::IniFiles; 1;}) {
	print STDERR "You're missing Config::IniFiles, try 'apt-get install libconfig-inifiles-perl'\n";
	exit 1;
}

32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
use Getopt::Long;
use IO::Select;
use IO::Socket;

use smradius::version;
use Radius::Packet;



# Display help
sub displayHelp {
	print(STDERR<<EOF);

Usage: $0 [args] <server> <acct|auth|disconnect> <secret>
    --raddb                Directory where the radius dictionary files are

EOF
Nigel Kukard's avatar
Nigel Kukard committed
49
50

	return;
51
52
53
}


54
print(STDERR "SMRadClient v".VERSION." - Copyright (c) 2007-2016, AllWorldIT\n");
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78

# Set defaults
my $cfg;
$cfg->{'config_file'} = "/etc/smradiusd.conf";


# Parse command line params
my $cmdline;
%{$cmdline} = ();
GetOptions(
		\%{$cmdline},
		"config:s",
		"raddb:s",
		"help",
) or die "Error parsing commandline arguments";

# Check for some args
if ($cmdline->{'help'}) {
	displayHelp();
	exit 0;
}

# Make sure we only have 2 additional args
if (@ARGV > 3 || @ARGV < 3) {
Nigel Kukard's avatar
Nigel Kukard committed
79
80
81
	print(STDERR "ERROR: Invalid number of arguments\n\n");
	displayHelp();
	exit 1;
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
}

if (!defined($cmdline->{'raddb'}) || $cmdline->{'raddb'} eq "") {
	print(STDERR "ERROR: No raddb directory specified!\n\n");
	displayHelp();
	exit 1;
}

# Get variables we need
my ($server,$type,$secret) = @ARGV;

# Validate type
if (!defined($type) || ( $type ne "acct" && $type ne "auth" &&
			$type ne "disconnect"
)){
	print(STDERR "ERROR: Invalid packet type specified!\n\n");
	displayHelp();
	exit 1;
}


#if (defined($cmdline->{'config'}) && $cmdline->{'config'} ne "") {
#	$cfg->{'config_file'} = $cmdline->{'config'};
#}

# Check config file exists
#if (! -f $cfg->{'config_file'}) {
#	die("No configuration file '".$cfg->{'config_file'}."' found!\n");
#}

# Use config file, ignore case
#tie my %inifile, 'Config::IniFiles', (
#		-file => $cfg->{'config_file'},
#		-nocase => 1
#) or die "Failed to open config file '".$cfg->{'config_file'}."': $!";
# Copy config
#my %config = %inifile;

print(STDERR "\n");


# Time to start loading the dictionary
print(STDERR "Loading dictionaries...");
Nigel Kukard's avatar
Nigel Kukard committed
125
my $raddb = Radius::Dictionary->new();
126

Nigel Kukard's avatar
Nigel Kukard committed
127
128
# Look for files in the dir
opendir(my $DIR, $cmdline->{'raddb'})
129
	or die "Cannot open '".$cmdline->{'raddb'}."': $!";
Nigel Kukard's avatar
Nigel Kukard committed
130
my @raddb_files = readdir($DIR);
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158

# And load the dictionary
foreach my $df (@raddb_files) {
	my $df_fn = $cmdline->{'raddb'}."/$df";
	# Load dictionary
	if (!$raddb->readfile($df_fn)) {
		print(STDERR "Failed to load dictionary '$df_fn': $!");
	}
	print(STDERR ".");
}
print(STDERR "\n");

# Decide what type of packet this is
my $port;
my $pkt_code;
if ($type eq "acct") {
	$port = 1813;
	$pkt_code = "Accounting-Request";
} elsif ($type eq "auth") {
	$port = 1812;
	$pkt_code = "Access-Request";
} elsif ($type eq "disconnect") {
	$port = 1813;
	$pkt_code = "Disconnect-Request";
}


print(STDERR "\nRequest:\n");
159
print(STDERR " > Secret => '$secret'\n");
160
161
162
163
# Build packet
my $pkt = Radius::Packet->new($raddb);
$pkt->set_code($pkt_code);
# Generate identifier
Nigel Kukard's avatar
Nigel Kukard committed
164
my $ident = int(rand(32768));
165
166
167
$pkt->set_identifier($ident);
print(STDERR " > Identifier: $ident\n");
# Generate authenticator number
Nigel Kukard's avatar
Nigel Kukard committed
168
my $authen = int(rand(32768));
169
170
171
172
$pkt->set_authenticator($authen);
print(STDERR " > Authenticator: $ident\n");

# Pull in attributes
Nigel Kukard's avatar
Nigel Kukard committed
173
while (my $line = <STDIN>) {
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
	# Remove EOL
	chomp($line);
	# Split on , and newline
	my @rawAttributes = split(/,\n/,$line);
	foreach my $attr (@rawAttributes) {
		# Pull off attribute name & value
		my ($name,$value) = ($attr =~ /\s*(\S+)\s*=\s?(.+)/);
		# Add to packet
		print(STDERR " > Adding '$name' => '$value'\n");
		if ($name eq "User-Password") {
			$pkt->set_password($value,$secret);
		} else {
			$pkt->set_attr($name,$value);
		}
	}
}

# Create UDP packet
my $udp_packet = $pkt->pack();

# Create socket to send packet out on
my $sockTimeout = "10";  # 10 second timeout
Nigel Kukard's avatar
Nigel Kukard committed
196
my $sock = IO::Socket::INET->new(
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
		PeerAddr => $server,
		PeerPort => $port,
		Type => SOCK_DGRAM,
		Proto => 'udp',
		TimeOut => $sockTimeout,
);

if (!$sock) {
	print(STDERR "ERROR: Failed to create socket\n");
}

# Check if we sent the packet...
if (!$sock->send($udp_packet)) {
	print(STDERR "ERROR: Failed to send data on socket\n");
	exit 1;
}


# And time for the response
print(STDERR "\nResponse:\n");

# Once sent, we need to get a response back
Nigel Kukard's avatar
Nigel Kukard committed
219
my $rsock = IO::Select->new($sock);
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
if (!$rsock) {
	print(STDERR "ERROR: Failed to select response data on socket\n");
	exit 1;
}

# Check if we can read a response after the select()
if (!$rsock->can_read($sockTimeout)) {
	print(STDERR "ERROR: Failed to receive response data on socket\n");
	exit 1;
}

# Read packet
$sock->recv($udp_packet, 65536);
if (!$udp_packet) {
	print(STDERR "ERROR: Receive response data failed: $!\n");
	exit 1;
}

# Parse packet
Nigel Kukard's avatar
Nigel Kukard committed
239
$pkt = Radius::Packet->new($raddb,$udp_packet);
240
241
242
243
244
245
print(STDERR " > Authenticated: ". (defined(auth_req_verify($udp_packet,$secret,$authen)) ? "yes" : "no") ."\n");
print(STDERR $pkt->str_dump());


1;
# vim: ts=4