]> git.stg.codes - stg.git/blob - projects/rlm_stg/stg_client.cpp
Fix encoding hint in documentation
[stg.git] / projects / rlm_stg / stg_client.cpp
1 /*
2  *    This program is free software; you can redistribute it and/or modify
3  *    it under the terms of the GNU General Public License as published by
4  *    the Free Software Foundation; either version 2 of the License, or
5  *    (at your option) any later version.
6  *
7  *    This program is distributed in the hope that it will be useful,
8  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
9  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  *    GNU General Public License for more details.
11  *
12  *    You should have received a copy of the GNU General Public License
13  *    along with this program; if not, write to the Free Software
14  *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
15  */
16
17 /*
18  *    Author : Maxim Mamontov <faust@stargazer.dp.ua>
19  */
20
21 /*
22  *  Realization of data access via Stargazer for RADIUS
23  *
24  *  $Revision: 1.8 $
25  *  $Date: 2010/04/16 12:30:02 $
26  *
27  */
28
29 #include <netdb.h>
30 #include <sys/types.h>
31 #include <unistd.h> // close
32
33 #include <cerrno>
34 #include <cstring>
35
36 #include <stdexcept>
37
38 #include "stg_client.h"
39
40 using namespace std;
41
42 void InitEncrypt(BLOWFISH_CTX * ctx, const std::string & password);
43 void Encrypt(BLOWFISH_CTX * ctx, char * dst, const char * src, int len8);
44 void Decrypt(BLOWFISH_CTX * ctx, char * dst, const char * src, int len8);
45
46 //-----------------------------------------------------------------------------
47 //-----------------------------------------------------------------------------
48 //-----------------------------------------------------------------------------
49 STG_CLIENT::STG_CLIENT(const std::string & host, uint16_t port, uint16_t lp, const std::string & pass)
50     : localPort(lp),
51       password(pass),
52       framedIP(0)
53 {
54 sock = socket(AF_INET, SOCK_DGRAM, 0);
55 if (sock == -1)
56     {
57     std::string message = strerror(errno);
58     message = "Socket create error: '" + message + "'";
59     throw std::runtime_error(message);
60     }
61
62 struct hostent * he = NULL;
63 he = gethostbyname(host.c_str());
64 if (he == NULL)
65     {
66     throw std::runtime_error("gethostbyname error");
67     }
68
69 outerAddr.sin_family = AF_INET;
70 outerAddr.sin_port = htons(port);
71 outerAddr.sin_addr.s_addr = *(uint32_t *)he->h_addr;
72
73 InitEncrypt(&ctx, password);
74
75 PrepareNet();
76 }
77 //-----------------------------------------------------------------------------
78 STG_CLIENT::~STG_CLIENT()
79 {
80 close(sock);
81 }
82 //-----------------------------------------------------------------------------
83 uint32_t STG_CLIENT::GetFramedIP() const
84 {
85 return framedIP;
86 }
87 //-----------------------------------------------------------------------------
88 int STG_CLIENT::PrepareNet()
89 {
90 if (localPort != 0)
91     {
92     struct sockaddr_in localAddr;
93     localAddr.sin_family = AF_INET;
94     localAddr.sin_port = htons(localPort);
95     localAddr.sin_addr.s_addr = inet_addr("0.0.0.0");;
96
97     if (bind(sock, (struct sockaddr *)&localAddr, sizeof(localAddr)))
98         {
99         errorStr = "Bind failed";
100         return -1;
101         }
102     }
103 return 0;
104 }
105 //-----------------------------------------------------------------------------
106 string STG_CLIENT::GetUserPassword() const
107 {
108 return userPassword;
109 }
110 //-----------------------------------------------------------------------------
111 int STG_CLIENT::Send(const RAD_PACKET & packet)
112 {
113 char buf[RAD_MAX_PACKET_LEN];
114     
115 Encrypt(&ctx, buf, (char *)&packet, sizeof(RAD_PACKET) / 8);
116
117 int res = sendto(sock, buf, sizeof(RAD_PACKET), 0, (struct sockaddr *)&outerAddr, sizeof(outerAddr));
118
119 if (res == -1)
120     errorStr = "Error sending data";
121
122 return res;
123 }
124 //-----------------------------------------------------------------------------
125 int STG_CLIENT::RecvData(RAD_PACKET * packet)
126 {
127 char buf[RAD_MAX_PACKET_LEN];
128 int res;
129
130 struct sockaddr_in addr;
131 socklen_t len = sizeof(struct sockaddr_in);
132
133 res = recvfrom(sock, buf, RAD_MAX_PACKET_LEN, 0, reinterpret_cast<struct sockaddr *>(&addr), &len);
134 if (res == -1)
135     {
136     errorStr = "Error receiving data";
137     return -1;
138     }
139
140 Decrypt(&ctx, (char *)packet, buf, res / 8);
141
142 return 0;
143 }
144 //-----------------------------------------------------------------------------
145 int STG_CLIENT::Request(RAD_PACKET * packet, const std::string & login, const std::string & svc, uint8_t packetType)
146 {
147 int res;
148
149 memcpy((void *)&packet->magic, (void *)RAD_ID, RAD_MAGIC_LEN);
150 packet->protoVer[0] = '0';
151 packet->protoVer[1] = '1';
152 packet->packetType = packetType;
153 packet->ip = 0;
154 strncpy((char *)packet->login, login.c_str(), RAD_LOGIN_LEN);
155 strncpy((char *)packet->service, svc.c_str(), RAD_SERVICE_LEN);
156
157 res = Send(*packet);
158 if (res == -1)
159     return -1;
160
161 res = RecvData(packet);
162 if (res == -1)
163     return -1;
164
165 if (strncmp((char *)packet->magic, RAD_ID, RAD_MAGIC_LEN))
166     {
167     errorStr = "Magic invalid. Wanted: '";
168     errorStr += RAD_ID;
169     errorStr += "', got: '";
170     errorStr += (char *)packet->magic;
171     errorStr += "'";
172     return -1;
173     }
174
175 return 0;
176 }
177 //-----------------------------------------------------------------------------
178 int STG_CLIENT::Authorize(const string & login, const string & svc)
179 {
180 RAD_PACKET packet;
181
182 userPassword = "";
183
184 if (Request(&packet, login, svc, RAD_AUTZ_PACKET))
185     return -1;
186
187 if (packet.packetType != RAD_ACCEPT_PACKET)
188     return -1;
189
190 userPassword = (char *)packet.password;
191
192 return 0;
193 }
194 //-----------------------------------------------------------------------------
195 int STG_CLIENT::Authenticate(const string & login, const string & svc)
196 {
197 RAD_PACKET packet;
198
199 userPassword = "";
200
201 if (Request(&packet, login, svc, RAD_AUTH_PACKET))
202     return -1;
203
204 if (packet.packetType != RAD_ACCEPT_PACKET)
205     return -1;
206
207 return 0;
208 }
209 //-----------------------------------------------------------------------------
210 int STG_CLIENT::PostAuthenticate(const string & login, const string & svc)
211 {
212 RAD_PACKET packet;
213
214 userPassword = "";
215
216 if (Request(&packet, login, svc, RAD_POST_AUTH_PACKET))
217     return -1;
218
219 if (packet.packetType != RAD_ACCEPT_PACKET)
220     return -1;
221
222 if (svc == "Framed-User")
223     framedIP = packet.ip;
224 else
225     framedIP = 0;
226
227 return 0;
228 }
229 //-----------------------------------------------------------------------------
230 int STG_CLIENT::Account(const std::string & type, const string & login, const string & svc, const string & sessid)
231 {
232 RAD_PACKET packet;
233
234 userPassword = "";
235 strncpy((char *)packet.sessid, sessid.c_str(), RAD_SESSID_LEN);
236
237 if (type == "Start")
238     {
239     if (Request(&packet, login, svc, RAD_ACCT_START_PACKET))
240         return -1;
241     }
242 else if (type == "Stop")
243     {
244     if (Request(&packet, login, svc, RAD_ACCT_STOP_PACKET))
245         return -1;
246     }
247 else if (type == "Interim-Update")
248     {
249     if (Request(&packet, login, svc, RAD_ACCT_UPDATE_PACKET))
250         return -1;
251     }
252 else
253     {
254     if (Request(&packet, login, svc, RAD_ACCT_OTHER_PACKET))
255         return -1;
256     }
257
258 if (packet.packetType != RAD_ACCEPT_PACKET)
259     return -1;
260
261 return 0;
262 }
263 //-----------------------------------------------------------------------------
264 inline
265 void Encrypt(BLOWFISH_CTX * ctx, char * dst, const char * src, int len8)         
266 {
267 // len8 - длина в 8-ми байтовых блоках                                                   
268 if (dst != src) 
269     memcpy(dst, src, len8 * 8);                                                          
270     
271 for (int i = 0; i < len8; i++)
272     Blowfish_Encrypt(ctx, (uint32_t *)(dst + i*8), (uint32_t *)(dst + i*8 + 4));
273 }
274 //-----------------------------------------------------------------------------
275 inline
276 void Decrypt(BLOWFISH_CTX * ctx, char * dst, const char * src, int len8)
277 {
278 // len8 - длина в 8-ми байтовых блоках
279 if (dst != src)
280     memcpy(dst, src, len8 * 8);
281
282 for (int i = 0; i < len8; i++)
283     Blowfish_Decrypt(ctx, (uint32_t *)(dst + i*8), (uint32_t *)(dst + i*8 + 4));
284 }
285 //-----------------------------------------------------------------------------
286 inline
287 void InitEncrypt(BLOWFISH_CTX * ctx, const std::string & password)
288 {
289 unsigned char keyL[RAD_PASSWORD_LEN];
290 memset(keyL, 0, RAD_PASSWORD_LEN);
291 strncpy((char *)keyL, password.c_str(), RAD_PASSWORD_LEN);
292 Blowfish_Init(ctx, keyL, RAD_PASSWORD_LEN);
293 }
294 //-----------------------------------------------------------------------------