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