1 /* The long-awaited radius check */
2
3 #include "config.h"
4
5 /* our local structure that we deal with */
6 struct radius_data {
7 unsigned char seq;
8 int packetsent;
9 time_t lastsent;
10 };
11
12 /* see rfc 2138, section 3 */
13
14 struct radius_packet_head {
15 unsigned char code;
16 unsigned char identifier;
17 unsigned short int length;
18 unsigned char authenticator[16];
19 };
20
21 void send_radius_packet(int, struct monitorent *, int);
22
23 unsigned char rad_seq = 1;
24
25 #define RADIUS_Access_Request 1
26 #define RADIUS_Access_Accept 2
27 #define RADIUS_Access_Reject 3
28
print_in_hex(unsigned char * message,int msgsize)29 void print_in_hex(unsigned char *message, int msgsize)
30 {
31 int x;
32 for (x =0;x<msgsize;x++)
33 {
34 if ((message[x] > 0) && (message[x] < 26))
35 fprintf(stderr, "0x%-2.2x ", message[x]);
36 else if (message[x] == 0)
37 fprintf(stderr, "0x%-2.2x ", message[x]);
38 else
39 fprintf(stderr, "0x%-2.2x ", message[x]);
40 if ((x != 0) && (((x+1) %16) == 0))
41 fprintf(stderr, "\n");
42 }
43 fprintf(stderr, "\n");
44
45 }
46
47
48 /*
49 * Do the setup and initalization of the radius check
50 */
start_check_radius(struct monitorent * here,time_t now_t)51 void start_check_radius(struct monitorent *here, time_t now_t)
52 {
53 struct radius_data *localstruct = NULL;
54 struct my_hostent *hp = NULL;
55 struct sockaddr_in name;
56 int serrno = -1;
57 int errcode = 0;
58
59 hp = my_gethostbyname(here->checkent->hostname, AF_INET);
60
61 if (hp == NULL)
62 {
63 here->retval = SYSM_NODNS;
64 return;
65 }
66
67 /* Allocate our memory */
68 here->monitordata = MALLOC(sizeof(struct radius_data), "radius localstruct");
69 if (here->monitordata == NULL)
70 {
71 print_err(1, "radius.c: MALLOC failed");
72 return;
73 }
74 memset(here->monitordata, 0, sizeof(struct radius_data));
75 localstruct = here->monitordata;
76
77 here->filedes = udp_open_sock();
78 if (here->filedes == -1)
79 {
80 print_err(1, "radius.c: udp_open_sock() failed while checking %s", here->checkent->hostname);
81 FREE(here->monitordata);
82 here->retval = here->checkent->lastcheck;
83 return;
84 }
85
86 /* setup the name structure */
87 memset(&name, 0, sizeof(name));
88
89 /* copy the remote address into the strcture */
90 memcpy((char*)&name.sin_addr, (char*)hp->my_h_addr_v4, hp->h_length_v4);
91
92 /* internet, what is that? */
93 name.sin_family = AF_INET;
94
95 /* radius can use a few different port numbers.. allow
96 them to specify in conf file */
97
98 name.sin_port = htons(here->checkent->port);
99
100 errcode = connect(here->filedes, (struct sockaddr *)&name,
101 sizeof(struct sockaddr_in));
102
103 serrno = errno;
104
105 if (errcode != 0)
106 {
107 perror("radius.c: connect");
108 close(here->filedes);
109 FREE(here->monitordata);
110 switch (serrno)
111 {
112 case ECONNREFUSED:
113 case EINTR:
114 here->retval = SYSM_CONNREF;
115 break;
116 case ENETUNREACH:
117 here->retval = SYSM_NETUNRCH;
118 break;
119 case EHOSTDOWN:
120 case EHOSTUNREACH:
121 here->retval = SYSM_HOSTDOWN;
122 break;
123 case ETIMEDOUT:
124 here->retval = SYSM_TIMEDOUT;
125 break;
126 }
127 return;
128 }
129
130 localstruct->seq = rad_seq++;
131
132 /* send radius-access-request packet */
133 send_radius_packet(here->filedes, here, localstruct->seq);
134 localstruct->packetsent++;
135 localstruct->lastsent = now_t;
136 /* If this return is reached, service_check_radius will be
137 called later */
138 return;
139 }
140
service_check_radius(struct monitorent * here,time_t now_t)141 void service_check_radius(struct monitorent *here, time_t now_t)
142 {
143 struct radius_data *localstruct = NULL;
144
145 unsigned char response[4096];
146 int ret;
147
148 localstruct = here->monitordata;
149 if (now_t-localstruct->lastsent < 1)
150 {
151 return;
152 }
153
154 if (localstruct->packetsent > 10)
155 {
156 here->retval = SYSM_NORESP;
157 close(here->filedes);
158 FREE(localstruct);
159 here->monitordata = NULL;
160 return;
161 }
162
163
164 if (data_waiting_read(here->filedes, 0))
165 {
166 ret = read(here->filedes, response, 4096);
167
168 if (ret == -1)
169 {
170 switch (errno)
171 {
172 case ECONNREFUSED:
173 case EINTR:
174 here->retval = SYSM_CONNREF;
175 break;
176 case ENETUNREACH:
177 here->retval = SYSM_NETUNRCH;
178 break;
179 case EHOSTDOWN:
180 case EHOSTUNREACH:
181 here->retval = SYSM_HOSTDOWN;
182 break;
183 case ETIMEDOUT:
184 here->retval = SYSM_TIMEDOUT;
185 break;
186 default:
187 perror("radius.c:read");
188 print_err(0, "radius.c:reading radius response");
189 print_err(0, "radius.c:leaving state alone");
190 here->retval = here->checkent->lastcheck;
191 }
192 } else if (ret > 0) {
193 if (response[0] == 2)
194 {
195 here->retval = SYSM_OK;
196 } else if (response[0] == 3) {
197 here->retval = SYSM_BAD_AUTH;
198 } else {
199 print_err(0, "radius.c:Unknown response");
200 print_in_hex(response, ret);
201 }
202 }
203 close(here->filedes);
204 FREE(localstruct);
205 return;
206 }
207 /* send_packet */
208
209 send_radius_packet(here->filedes, here, localstruct->seq);
210
211 /* increment packetsent */
212
213 localstruct->packetsent++;
214 localstruct->lastsent = now_t;
215
216
217 return;
218 }
219
220 /*
221 * Stop the check, and free any pending memory to be
222 * returned to the main processor pool
223 */
stop_check_radius(struct monitorent * here)224 void stop_check_radius(struct monitorent *here)
225 {
226 struct radius_data *localstruct = NULL;
227
228 localstruct = here->monitordata;
229 if (localstruct != NULL)
230 {
231 close(here->filedes);
232 FREE(localstruct);
233 here->monitordata = NULL;
234 }
235 return;
236 }
237
238 /*
239 * Do the md5 sum of the RA stuff for the packet
240 *
241 */
calculate_RA(unsigned char * RA,unsigned char * packet,unsigned int packetlen,unsigned char * Secret)242 void calculate_RA(unsigned char *RA, unsigned char *packet,
243 unsigned int packetlen, unsigned char *Secret)
244 {
245 unsigned char buffer[256];
246 unsigned char temp_pkt[4096];
247 int secretlen;
248 int md5sumlen;
249
250 secretlen = strlen(Secret);
251 md5sumlen = (secretlen+packetlen);
252
253 memset(buffer, 0, 256);
254 memset(temp_pkt, 0, 4096);
255
256 memcpy(temp_pkt, packet, packetlen);
257 memcpy(temp_pkt+packetlen, Secret, secretlen);
258
259 md5_calc(RA, temp_pkt, md5sumlen);
260
261 }
262
gen_passwd(unsigned char * passwd_resp,int * resp_len,char * cleartext_pw,char * secret,unsigned char * request_authenticator)263 void gen_passwd(unsigned char *passwd_resp, int *resp_len, char *cleartext_pw,
264 char *secret, unsigned char *request_authenticator)
265 {
266 unsigned char *ptr;
267 int pw_len;
268 int secretlen = strlen(secret);
269 unsigned char md5buf[130];
270 unsigned char pw_digest[17];
271 int i;
272 int pass;
273 int passes;
274
275 /* Allocate temp space to work on pw, because of following,
276 excerpted from rfc2138 5.2
277
278 On transmission, the password is hidden. The password is first
279 padded at the end with nulls to a multiple of 16 octets. A one-
280 way MD5 hash is calculated over a stream of octets consisting of
281 the shared secret followed by the Request Authenticator. This
282 value is XORed with the first 16 octet segment of the password and
283 placed in the first 16 octets of the String field of the User-
284 Password Attribute.
285
286 */
287
288 pw_len = strlen(cleartext_pw);
289 if (pw_len > 255)
290 pw_len = 255;
291
292 passes = MAX(1, (pw_len+15)/16);
293
294 memset(passwd_resp, 0, 256);
295 memcpy(passwd_resp, cleartext_pw, strlen(cleartext_pw));
296
297 memcpy(md5buf, secret, secretlen);
298 memcpy(md5buf+secretlen, request_authenticator, 16);
299
300 ptr = (char *) passwd_resp;
301
302 for (pass = 0; pass < passes; pass++)
303 {
304 md5_calc (pw_digest, md5buf, secretlen + 16);
305 for (i = 0; i < 16; i++)
306 {
307 ptr[i] ^= pw_digest[i];
308 }
309 memcpy ((char *) md5buf + secretlen, (char *) ptr, 16);
310 ptr += 16;
311 }
312 memset(md5buf, 0, secretlen);
313 *resp_len = (pass*16);
314
315 }
316
gen_ra(char * data,int len)317 void gen_ra(char *data, int len)
318 {
319 int x;
320 for (x = 0; x < len ; x++)
321 data[x] = rand();
322 }
323
324
325 /*
326 * Form and send the access-request packet
327 */
send_radius_packet(int filedes,struct monitorent * here,int seq)328 void send_radius_packet(int filedes, struct monitorent *here, int seq)
329 {
330 /* Send the Packet */
331 unsigned char packet[1024];
332 struct radius_packet_head *radpkt;
333 int packetindex = 0;
334 int ret;
335 int pwlen = 0;
336
337 memset(packet, 0, 1024);
338 radpkt = (struct radius_packet_head *)&packet;
339
340 radpkt->code = RADIUS_Access_Request;
341 radpkt->identifier = seq;
342 gen_ra(packet+4, 16);
343
344 packetindex = 20;
345 /* add username */
346
347 packet[20] = 1;
348 packet[21] = (strlen(here->checkent->username)+2);
349 memcpy(packet+packetindex+2, here->checkent->username, (packet[21]-2));
350 packetindex = packetindex+ packet[21];
351
352 /* add password */
353 packet[packetindex] = 2;
354 gen_passwd(packet+packetindex+2, &pwlen, here->checkent->password,
355 here->checkent->secret, packet+4);
356 packet[packetindex+1] = 2+pwlen;
357 packetindex = packetindex+2+pwlen;
358
359 /* set service-type = 8 - authenticate-only */
360
361 packet[packetindex] = 6;
362 packetindex++;
363 packet[packetindex] = 6;
364 packetindex++;
365 packet[packetindex] = 0;
366 packet[packetindex+1] = 0;
367 packet[packetindex+2] = 0;
368 packet[packetindex+3] = 8;
369 packetindex = packetindex+4;
370
371 packet[packetindex] = 32;
372 packetindex++;
373 packet[packetindex] = 8;
374 packetindex++;
375 strcpy(packet+packetindex, "sysmon");
376 packetindex += 6;
377
378 packet[packetindex] = 61;
379 packetindex++;
380 packet[packetindex] = 6;
381 packetindex++;
382 packet[packetindex] = 0;
383 packetindex++;
384 packet[packetindex] = 0;
385 packetindex++;
386 packet[packetindex] = 0;
387 packetindex++;
388 packet[packetindex] = 5;
389 packetindex++;
390
391 packet[3] = packetindex;
392
393
394 ret = write(filedes, packet, packetindex);
395 if (ret == -1)
396 {
397 perror("write");
398 }
399
400 /* send packet */
401
402 }
403
404