-
Notifications
You must be signed in to change notification settings - Fork 1
/
TacacsSharpClient.cs
134 lines (116 loc) · 6.79 KB
/
TacacsSharpClient.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
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
125
126
127
128
129
130
131
132
133
134
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Threading.Tasks;
using TacacsSharp.Authentication;
namespace TacacsSharp
{
public class TacacsSharpClient
{
private string serverIp;
private int serverPort;
private string sharedKey;
private bool isEncryptionActive;
public TacacsSharpClient(string serverIp, int serverPort = 49, string sharedKey = null)
{
this.serverIp = serverIp;
this.serverPort = serverPort;
this.sharedKey = sharedKey;
isEncryptionActive = (!string.IsNullOrEmpty(sharedKey) && !string.IsNullOrWhiteSpace(sharedKey));
}
private byte[] SendAndReceiveData(TcpClient client, byte[] data)
{
var s = client.GetStream();
if(s.CanWrite) s.Write(data, 0 , data.Length);
var buffer = new byte[client.ReceiveBufferSize];
s.Read(buffer, 0, (int)client.ReceiveBufferSize);
return buffer;
}
private async Task<byte[]> SendAndReceiveDataAsync(TcpClient client, byte[] data)
{
var s = client.GetStream();
if(s.CanWrite) s.Write(data, 0 , data.Length);
var buffer = new byte[client.ReceiveBufferSize];
await s.ReadAsync(buffer, 0, (int)client.ReceiveBufferSize);
return buffer;
}
private IEnumerable<byte> MergeHeaderWithBody(PacketHeader header, byte[] bodyBytes)
=> isEncryptionActive? header.ToArray().Concat(Encryptor.Encrypt(header.SessionId, sharedKey, 192, header.SeqNumber, bodyBytes))
: header.ToArray().Concat(bodyBytes);
private Tuple<PacketHeader, byte[]> UnmergeHeaderAndBody(byte[] bytesFromServer)
{
using(var br = new BinaryReader(new MemoryStream(bytesFromServer)))
{
var recvHeader = PacketHeader.Parse(br.ReadBytes(12));
var recvBodyBytes = br.ReadBytes(recvHeader.BodyLength);
if(isEncryptionActive) recvBodyBytes = Encryptor.Decrypt(recvHeader.SessionId, sharedKey, 192, recvHeader.SeqNumber, recvBodyBytes).ToArray();
return new Tuple<PacketHeader, byte[]>(recvHeader, recvBodyBytes);
}
}
public async Task<AuthenticationStatus> AuthenticateAsciiAsync(string user, string pass, string remoteAddr, string port,
PrivilegeLevel privLev = PrivilegeLevel.TAC_PLUS_PRIV_LVL_MAX, AuthenticationService authService = AuthenticationService.TAC_PLUS_AUTHEN_SVC_LOGIN)
{
var authStartBytes = new AuthenticationStartPacketBody(privLev, AuthenticationType.TAC_PLUS_AUTHEN_TYPE_ASCII, authService, IPAddress.Parse(remoteAddr), port).ToArray();
var header = new PacketHeader(
PacketType.TAC_PLUS_AUTHEN, 1,
isEncryptionActive ? EncryptionFlag.TAC_PLUS_UNENCRYPTED_FLAG : EncryptionFlag.TAC_PLUS_ENCRYPTED_FLAG,
authStartBytes.Length
);
using(TcpClient client = new TcpClient(serverIp, serverPort))
{
var recvData = UnmergeHeaderAndBody(await SendAndReceiveDataAsync(client, MergeHeaderWithBody(header, authStartBytes).ToArray()));
var recvHeader = recvData.Item1;
if(AuthenticationReplyPacketBody.Parse(recvData.Item2).AuthStatus == AuthenticationStatus.GETUSER)
{
var continuePacket = new AuthenticationContinuePacketBody(CommunicationFlag.CONTINUES, user);
recvHeader.SeqNumber++;
recvHeader.BodyLength = continuePacket.ToArray().Count();
recvData = UnmergeHeaderAndBody(await SendAndReceiveDataAsync(client, MergeHeaderWithBody(recvHeader, continuePacket.ToArray()).ToArray()));
recvHeader = recvData.Item1;
if(AuthenticationReplyPacketBody.Parse(recvData.Item2).AuthStatus == AuthenticationStatus.GETPASS)
{
continuePacket = new AuthenticationContinuePacketBody(CommunicationFlag.CONTINUES, pass);
recvHeader.SeqNumber++;
recvHeader.BodyLength = continuePacket.ToArray().Count();
recvData = UnmergeHeaderAndBody(await SendAndReceiveDataAsync(client, MergeHeaderWithBody(recvHeader, continuePacket.ToArray()).ToArray()));
}
}
return AuthenticationReplyPacketBody.Parse(recvData.Item2).AuthStatus;
}
}
public AuthenticationStatus AuthenticateAscii(string user, string pass, string remoteAddr, string port,
PrivilegeLevel privLev = PrivilegeLevel.TAC_PLUS_PRIV_LVL_MAX, AuthenticationService authService = AuthenticationService.TAC_PLUS_AUTHEN_SVC_LOGIN)
{
var authStartBytes = new AuthenticationStartPacketBody(privLev, AuthenticationType.TAC_PLUS_AUTHEN_TYPE_ASCII, authService, IPAddress.Parse(remoteAddr), port).ToArray();
var header = new PacketHeader(
PacketType.TAC_PLUS_AUTHEN, 1,
isEncryptionActive ? EncryptionFlag.TAC_PLUS_UNENCRYPTED_FLAG : EncryptionFlag.TAC_PLUS_ENCRYPTED_FLAG,
authStartBytes.Length
);
using(TcpClient client = new TcpClient(serverIp, serverPort))
{
var recvData = UnmergeHeaderAndBody(SendAndReceiveData(client, MergeHeaderWithBody(header, authStartBytes).ToArray()));
var recvHeader = recvData.Item1;
if(AuthenticationReplyPacketBody.Parse(recvData.Item2).AuthStatus == AuthenticationStatus.GETUSER)
{
var continuePacket = new AuthenticationContinuePacketBody(CommunicationFlag.CONTINUES, user);
recvHeader.SeqNumber++;
recvHeader.BodyLength = continuePacket.ToArray().Count();
recvData = UnmergeHeaderAndBody(SendAndReceiveData(client, MergeHeaderWithBody(recvHeader, continuePacket.ToArray()).ToArray()));
recvHeader = recvData.Item1;
if(AuthenticationReplyPacketBody.Parse(recvData.Item2).AuthStatus == AuthenticationStatus.GETPASS)
{
continuePacket = new AuthenticationContinuePacketBody(CommunicationFlag.CONTINUES, pass);
recvHeader.SeqNumber++;
recvHeader.BodyLength = continuePacket.ToArray().Count();
recvData = UnmergeHeaderAndBody(SendAndReceiveData(client, MergeHeaderWithBody(recvHeader, continuePacket.ToArray()).ToArray()));
}
}
return AuthenticationReplyPacketBody.Parse(recvData.Item2).AuthStatus;
}
}
}
}