1 /* This file is part of GNU Radius.
2    Copyright (C) 2003,2004,2006,2007,2008 Free Software Foundation, Inc.
3 
4    Written by Sergey Poznyakoff
5 
6    GNU Radius is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10 
11    GNU Radius is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15 
16    You should have received a copy of the GNU General Public License
17    along with GNU Radius; if not, write to the Free Software Foundation,
18    Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
19 
20 /* RPP stands for Radius Process Pool */
21 
22 #ifdef HAVE_CONFIG_H
23 # include <config.h>
24 #endif
25 #include <sys/types.h>
26 #include <sys/wait.h>
27 #include <unistd.h>
28 #include <errno.h>
29 
30 #include <radiusd.h>
31 
32 static int rpp_stdin;
33 static int rpp_stdout;
34 
35 /* Process intercommunication primitives */
36 
37 enum process_status {
38 	process_busy,      /* Process is busy handling a request */
39 	process_ready,     /* Precess is idle and ready for input */
40 	process_finished   /* Process has finished */
41 };
42 
43 typedef struct {
44 	pid_t pid;    /* PID of the handler process */
45 	int p[2];     /* IPC descriptors. p[0] - input, p[1] - output */
46 	enum process_status status; /* Current process status */
47 	int exit_status;  /* Process exit status if status==process_finished */
48 } rpp_proc_t;
49 
50 
51 /* Low-level calls */
52 
53 /* Write into the pipe (represented by FD) SIZE bytes from PTR. TV
54    sets timeout. TV==NULL means no timeout is imposed.
55 
56    Returns number of bytes written */
57 static int
pipe_write(int fd,void * ptr,size_t size,struct timeval * tv)58 pipe_write(int fd, void *ptr, size_t size, struct timeval *tv)
59 {
60 	errno = 0;
61 	if (!tv)
62 		return write(fd, ptr, size);
63 	else {
64 		char *data = ptr;
65 		int rc;
66 		struct timeval tval, start;
67 		fd_set wr_set;
68 		size_t n;
69 
70 		gettimeofday(&start, NULL);
71 		for (n = 0; n < size;) {
72 
73 			FD_ZERO(&wr_set);
74 			FD_SET(fd, &wr_set);
75 
76 			tval = *tv;
77 			if (grad_recompute_timeout (&start, &tval)) {
78 				errno = ETIMEDOUT;
79 				break;
80 			}
81 
82 			rc = select(fd + 1, NULL, &wr_set, NULL, &tval);
83 			if (rc == 0) {
84 				errno = ETIMEDOUT;
85 				GRAD_DEBUG(100, "rc = 0");
86 				break;
87 			} else if (rc < 0) {
88 				if (errno == EINTR)
89 					continue;
90 				GRAD_DEBUG2(100, "rc = %d, errno = %d",
91                                             rc, errno);
92 				break;
93 			} else if (rc > 0) {
94 				rc = write(fd, data, 1);
95 				if (rc != 1) {
96 					GRAD_DEBUG2(100, "rc = %d, errno = %d",
97                                                     rc, errno);
98 					break;
99 				}
100 				data++;
101 				n++;
102 			}
103 		}
104 		GRAD_DEBUG1(100,"n = %d",n);
105 		return n;
106 	}
107 }
108 
109 /* Read from the pipe (represented by FD) at most SIZE bytes into PTR. TV
110    sets timeout. TV==NULL means no timeout is imposed.
111 
112    Returns number of bytes read */
113 static int
pipe_read(int fd,void * ptr,size_t size,struct timeval * tv)114 pipe_read(int fd, void *ptr, size_t size, struct timeval *tv)
115 {
116 	char *data = ptr;
117 	int rc;
118 
119 	errno = 0;
120 	if (!tv) {
121 		int rdbytes = 0;
122 		do {
123 			rc = read(fd, data, size);
124 			if (rc > 0) {
125 				data += rc;
126 				size -= rc;
127 				rdbytes += rc;
128 			} else if (errno != EINTR)
129 				break;
130 		} while (size > 0);
131 		return rdbytes;
132 	} else {
133 		struct timeval tval, start;
134 		fd_set rd_set;
135 		size_t n;
136 
137 		gettimeofday(&start, NULL);
138 		for (n = 0; n < size;) {
139 
140 			FD_ZERO(&rd_set);
141 			FD_SET(fd, &rd_set);
142 
143 			tval = *tv;
144 			if (grad_recompute_timeout (&start, &tval)) {
145 				errno = ETIMEDOUT;
146 				break;
147 			}
148 
149 			rc = select(fd + 1, &rd_set, NULL, NULL, &tval);
150 			if (rc == 0) {
151 				errno = ETIMEDOUT;
152 				break;
153 			}
154 			if (rc < 0) {
155 				if (errno == EINTR)
156 					continue;
157 				break;
158 			} else if (rc > 0) {
159 				rc = read(fd, data, 1);
160 				if (rc != 1)
161 					break;
162 				data++;
163 				n++;
164 			}
165 		}
166 		return n;
167 	}
168 }
169 
170 
171 /* RPP layer I/O. Each packet transmitted over a pipe is preceeded by
172    its length (a size_t number in host order) */
173 
174 /* Read SIZE bytes from the pipe (FD) into DATA. TV sets timeout */
175 static int
rpp_fd_read(int fd,void * data,size_t size,struct timeval * tv)176 rpp_fd_read(int fd, void *data, size_t size, struct timeval *tv)
177 {
178 	size_t sz, nbytes = 0;
179 
180 	sz = pipe_read(fd, &nbytes, sizeof(nbytes), tv);
181 	if (sz == 0)
182 		return 0; /* eof */
183 	GRAD_DEBUG1(100,"nbytes=%lu",nbytes);
184 	if (sz != sizeof(nbytes))
185 		return -1;
186 	sz = nbytes > size ? size : nbytes;
187 	if (pipe_read (fd, data, sz, tv) != sz)
188 		return -2;
189 	for (;nbytes > size; nbytes--) {
190 		char c;
191 		if (pipe_read(fd, &c, 1, tv) != 1)
192 			return -3;
193 	}
194 
195 	GRAD_DEBUG1(100,"return %lu", (unsigned long)sz);
196 	return sz;
197 }
198 
199 /* Write SIZE bytes from DATA to the pipe FD. TV sets timeout */
200 static int
rpp_fd_write(int fd,void * data,size_t size,struct timeval * tv)201 rpp_fd_write(int fd, void *data, size_t size, struct timeval *tv)
202 {
203 	int rc;
204 	GRAD_DEBUG1(100,"size=%lu",size);
205 	if (pipe_write(fd, &size, sizeof(size), tv) != sizeof(size))
206 		return -1;
207 	if (pipe_write(fd, data, size, tv) != size)
208 		return -2;
209 	GRAD_DEBUG1(1,"return %lu", (unsigned long)size);
210 	return size;
211 }
212 
213 
214 
215 /* Start a handler process. PROC_MAIN is the handler function (process'
216    main loop). DATA is passed to PROC_MAIN verbatim.
217 
218    On success return 0 and fill in PROC structure. */
219 int
rpp_start_process(rpp_proc_t * proc,int (* proc_main)(void *),void * data)220 rpp_start_process(rpp_proc_t *proc, int (*proc_main)(void *), void *data)
221 {
222 	int inp[2];
223 	int outp[2];
224 	pid_t pid;
225 
226 	if (pipe(inp)) {
227 		grad_log(GRAD_LOG_ERR, "pipe(inp): %s", strerror(errno));
228 		return -1;
229 	}
230 
231 	if (pipe(outp)) {
232 		grad_log (GRAD_LOG_ERR, "pipe(outp): %s", strerror(errno));
233 		return -1;
234 	}
235 
236 	pid = fork();
237 	if (pid == -1) {
238 		grad_log (GRAD_LOG_ERR, "fork: %s", strerror(errno));
239 		return -1;
240 	}
241 	if (pid == 0) {
242 		/* Child */
243 		/* Close remote side of pipes */
244 		close(inp[0]);
245 		close(outp[1]);
246 		/* Close stdin */
247 		close(0);
248 		/* Redirect stdout to stderr */
249 		dup2(2, 1);
250 
251 		rpp_stdin = outp[0];
252 		rpp_stdout = inp[1];
253 
254 		/* Run the main process */
255 		exit(proc_main(data));
256 	}
257 
258 	/* Parent */
259 	close (inp[1]);
260 	close (outp[0]);
261 
262 	proc->pid = pid;
263 	proc->p[0] = inp[0];
264 	proc->p[1] = outp[1];
265 	proc->status = process_ready;
266 	return 0;
267 }
268 
269 
270 
271 static grad_list_t *process_list; /* List of rpp_proc_t */
272 
273 /* Look up the rpp_proc_t whose input descriptor is FD */
274 rpp_proc_t *
rpp_lookup_fd(int fd)275 rpp_lookup_fd(int fd)
276 {
277 	rpp_proc_t *p;
278 	grad_iterator_t *itr = grad_iterator_create(process_list);
279 	for (p = grad_iterator_first(itr); p; p = grad_iterator_next(itr))
280 		if (p->p[0] == fd)
281 			break;
282 	grad_iterator_destroy(&itr);
283 	return p;
284 }
285 
286 /* Find an rpp_proc_t ready for handling the reqest. If none is found,
287    start a new one. PROC_MAIN and DATA have the same meaning as in
288    rpp_start_process() */
289 rpp_proc_t *
rpp_lookup_ready(int (* proc_main)(void *),void * data)290 rpp_lookup_ready(int (*proc_main)(void *), void *data)
291 {
292 	rpp_proc_t *p;
293 
294 	if (process_list) {
295 		grad_iterator_t *itr = grad_iterator_create(process_list);
296 		for (p = grad_iterator_first(itr);
297 		     p && p->status != process_ready;
298 		     p = grad_iterator_next(itr))
299 			;
300 		grad_iterator_destroy(&itr);
301 	} else {
302 		process_list = grad_list_create();
303 		p = NULL;
304 	}
305 
306 	if (!p) {
307 		rpp_proc_t proc;
308 		if (grad_list_count(process_list) == max_children)
309 			return NULL;
310 		if (rpp_start_process(&proc, proc_main, data))
311 			return NULL;
312 		radiusd_register_input_fd("rpp", proc.p[0], NULL);
313 		p = grad_emalloc(sizeof(*p));
314 		*p = proc;
315 		grad_list_append(process_list, p);
316 	}
317 	return p;
318 }
319 
320 /* Find the rpp_proc_t with a given PID */
321 static int
rpp_comparator(const void * item,const void * data)322 rpp_comparator(const void *item, const void *data)
323 {
324 	const rpp_proc_t *p = item;
325 	const pid_t *pid = data;
326 	return p->pid != *pid;
327 }
328 
329 /* NOTE: Do not use any memory allocation calls */
330 rpp_proc_t *
rpp_lookup_pid(pid_t pid)331 rpp_lookup_pid(pid_t pid)
332 {
333 	return grad_list_locate(process_list, &pid, rpp_comparator);
334 }
335 
336 /* Remove the given rpp_proc_t from the list. The underlying process
337    is supposed to have finished. No diagnostics is output. */
338 static void
_rpp_remove(rpp_proc_t * p)339 _rpp_remove(rpp_proc_t *p)
340 {
341 	close(p->p[0]);
342 	close(p->p[1]);
343 	radiusd_close_channel(p->p[0]);
344 	if (grad_list_remove(process_list, p, NULL))
345 		grad_free(p);
346 }
347 
348 /* Remove the given rpp_proc_t from the list. Output diagnostics about
349    exit status of the handler */
350 void
rpp_remove(rpp_proc_t * p)351 rpp_remove(rpp_proc_t *p)
352 {
353 	char buffer[128];
354 	format_exit_status(buffer, sizeof buffer, p->exit_status);
355 	grad_log(GRAD_LOG_NOTICE, _("child %lu %s"),
356 		 (unsigned long) p->pid, buffer);
357 	_rpp_remove(p);
358 }
359 
360 /* Remove the rpp entry with given PID */
361 void
rpp_remove_pid(pid_t pid)362 rpp_remove_pid(pid_t pid)
363 {
364 	rpp_proc_t *p = rpp_lookup_pid(pid);
365 	if (p)
366 		rpp_remove(p);
367 }
368 
369 /* Reflect the change of state of the rpp handler process.
370 
371    The function is safe to be used from signal handlers */
372 void
rpp_status_changed(pid_t pid,int exit_status)373 rpp_status_changed(pid_t pid, int exit_status)
374 {
375 	rpp_proc_t *p = rpp_lookup_pid(pid);
376 	if (p) {
377 		p->status = process_finished;
378 		p->exit_status = exit_status;
379 	}
380 }
381 
382 /* Collect rpp_proc's whose handler have exited. Free any associated
383    resources */
384 void
rpp_collect_exited()385 rpp_collect_exited()
386 {
387 	rpp_proc_t *p;
388 	grad_iterator_t *itr = grad_iterator_create(process_list);
389 	for (p = grad_iterator_first(itr); p; p = grad_iterator_next(itr)) {
390 		if (p->status == process_finished)
391 			rpp_remove(p);
392 	}
393 	grad_iterator_destroy(&itr);
394 }
395 
396 
397 static int rpp_request_handler(void *arg);
398 
399 /* Return 1 if rpp with the given PID is ready for input */
400 int
rpp_ready(pid_t pid)401 rpp_ready(pid_t pid)
402 {
403 	if (pid == 0) {
404 		if (rpp_lookup_ready(rpp_request_handler, NULL))
405 			return 1;
406 	} else {
407 		rpp_proc_t *p;
408 		grad_iterator_t *itr = grad_iterator_create(process_list);
409 
410 		for (p = grad_iterator_first(itr); p; p = grad_iterator_next(itr)) {
411 			if (p->pid == pid) {
412 				break;
413 			}
414 		}
415 	        grad_iterator_destroy(&itr);
416 		if (p && p->status == process_ready)
417 			return 1;
418 	}
419 	return 0;
420 }
421 
422 /* Traverse the rpp list until FUN returns non-zero or there are no
423    more busy handlers. While traversing, remove finished handlers. */
424 void
rpp_flush(int (* fun)(void *),void * closure)425 rpp_flush(int (*fun)(void*), void *closure)
426 {
427 	time_t t;
428 	unsigned count;
429 	grad_iterator_t *itr = grad_iterator_create(process_list);
430 
431 	time(&t);
432 
433 	do {
434 		rpp_proc_t *p;
435 		for (count = 0, p = grad_iterator_first(itr);
436 		     p;
437 		     p = grad_iterator_next(itr))
438 			switch (p->status) {
439 			case process_ready:
440 				break;
441 
442 			case process_busy:
443 				count++;
444 				break;
445 
446 			case process_finished:
447 				rpp_remove (p);
448 			}
449 	} while (count > 0 && (*fun)(closure) == 0);
450 	grad_iterator_destroy(&itr);
451 }
452 
453 static int
_kill_itr(void * item,void * data)454 _kill_itr(void *item, void *data)
455 {
456 	rpp_proc_t *p = item;
457 	kill(p->pid, *(int*)data);
458 	return 0;
459 }
460 
461 /* Deliver signal SIGNO to the handler with pid PID */
462 int
rpp_kill(pid_t pid,int signo)463 rpp_kill(pid_t pid, int signo)
464 {
465 	if (pid > 0) {
466 		rpp_proc_t *p = rpp_lookup_pid(pid);
467 		if (p) {
468 			kill(p->pid, signo);
469 			rpp_check_pid(p->pid);
470 		} else
471      		        return 1;
472 	} else
473 		grad_list_iterate(process_list, _kill_itr, &signo);
474 	return 0;
475 }
476 
477 pid_t
rpp_check_pid(pid_t pid)478 rpp_check_pid(pid_t pid)
479 {
480 	int status;
481 	rpp_proc_t *p = rpp_lookup_pid(pid);
482 	if (!p)
483 		return -1;
484 	if (p->status != process_finished) {
485 		pid_t npid = waitpid(pid, &status, WNOHANG);
486 		if (npid <= 0)
487 			return pid;
488 		rpp_status_changed(pid, status);
489 	}
490 	rpp_remove (p);
491 	return 0;
492 }
493 
494 /* Slay the child */
495 static void
_rpp_slay(rpp_proc_t * p,char * msg)496 _rpp_slay(rpp_proc_t *p, char *msg)
497 {
498 	grad_log(GRAD_LOG_NOTICE, _("Killing process %lu: %s"),
499                  (u_long) p->pid, msg);
500 	kill(p->pid, SIGKILL);
501 	_rpp_remove(p);
502 }
503 
504 /* Return number of the handlers registered in the process list */
505 size_t
rpp_count()506 rpp_count()
507 {
508 	return grad_list_count(process_list);
509 }
510 
511 
512 
513 struct rpp_request {
514 	int type;                    /* Request type */
515 	struct sockaddr_in srv_addr; /* Server address */
516 	struct sockaddr_in clt_addr; /* Sender address */
517 	int fd;                      /* Source descriptor */
518 	size_t size;                 /* Size of the raw data */
519 	/* Raw data follow */
520 };
521 
522 #define RPP_COMPLETE  0 /* Completion reply */
523 #define RPP_UPDATE    1 /* Update reply */
524 
525 struct rpp_reply {
526 	int code;
527 	size_t size;
528 	/* Data follows */
529 };
530 
531 /* Master: Forward a request to the child */
532 int
rpp_forward_request(REQUEST * req)533 rpp_forward_request(REQUEST *req)
534 {
535 	rpp_proc_t *p;
536 	struct rpp_request frq;
537 	struct timeval tv, *tvp;
538 
539 	if (req->child_id)
540 		p = rpp_lookup_pid(req->child_id);
541 	else
542 		p = rpp_lookup_ready(rpp_request_handler, NULL);
543 
544 	if (!p)
545 		return 1;
546 	GRAD_DEBUG1(1, "sending request to %d", p->pid);
547 
548 	frq.type = req->type;
549 	frq.srv_addr = req->srv_addr;
550 	frq.clt_addr = req->addr;
551 	frq.fd = req->fd;
552 	frq.size = req->rawsize;
553 
554 	p->status = process_busy;
555 	req->child_id = p->pid;
556 
557 	if (radiusd_write_timeout) {
558 		tv.tv_sec = radiusd_write_timeout;
559 		tv.tv_usec = 0;
560 		tvp = &tv;
561 	} else
562 		tvp = NULL;
563 
564  	if (rpp_fd_write(p->p[1], &frq, sizeof frq, tvp) != sizeof frq) {
565 		_rpp_slay(p, _("error writing header"));
566 		return 1;
567 	}
568 	if (rpp_fd_write(p->p[1], req->rawdata, req->rawsize, tvp) != req->rawsize) {
569 		_rpp_slay(p, _("error writing data"));
570 		return 1;
571 	}
572 	return 0;
573 }
574 
575 static void
child_cleanup()576 child_cleanup()
577 {
578 	pid_t pid;
579 	int status;
580 
581         for (;;) {
582 		pid = waitpid((pid_t)-1, &status, WNOHANG);
583                 if (pid <= 0)
584                         break;
585 		filter_cleanup(pid, status);
586 	}
587 }
588 
589 static RETSIGTYPE
sig_handler(int sig)590 sig_handler(int sig)
591 {
592         switch (sig) {
593 	case SIGHUP:
594 	case SIGUSR1:
595 	case SIGUSR2:
596 		/*Ignored*/
597 		break;
598 
599 	case SIGALRM:
600 		grad_log(GRAD_LOG_INFO, _("Child exiting on timeout."));
601 		/*FALLTHRU*/
602 
603 	case SIGTERM:
604 	case SIGQUIT:
605 		/* FIXME: Possibly unsafe, it calls free() etc. */
606 	        radiusd_exit0();
607 
608 	case SIGCHLD:
609 		child_cleanup();
610 		break;
611 
612 	case SIGPIPE:
613 		/*FIXME: Any special action? */
614 		break;
615 
616 	default:
617 		abort();
618 	}
619 	grad_reset_signal(sig, sig_handler);
620 }
621 
622 /* Main loop for a child process */
623 int
rpp_request_handler(void * arg ARG_UNUSED)624 rpp_request_handler(void *arg ARG_UNUSED)
625 {
626 	struct rpp_request frq;
627 	struct rpp_reply repl;
628 	char *data = NULL;
629 	size_t datasize = 0;
630 	REQUEST *req;
631 
632 	radiusd_signal_init(sig_handler);
633 	grad_set_signal(SIGALRM, sig_handler);
634 	request_init_queue();
635 
636 	while (1) {
637 		int rc;
638 		int len;
639 
640 		alarm(process_timeout);
641 		len = rpp_fd_read(rpp_stdin, &frq, sizeof frq, NULL);
642 		alarm(0);
643 		if (len != sizeof frq) {
644 			if (errno == EINTR)
645 				continue;
646 			grad_log(GRAD_LOG_ERR,
647 			         _("Child received malformed header (len = %d, error = %s)"),
648 			         len, strerror(errno));
649 			radiusd_exit0();
650 		}
651 
652 		if (datasize < frq.size) {
653 			datasize = frq.size;
654 			data = grad_erealloc(data, datasize);
655 		}
656 
657 		if (rpp_fd_read(rpp_stdin, data, frq.size, NULL) != frq.size) {
658 			grad_log(GRAD_LOG_ERR,
659 			         _("Child received malformed data"));
660 			radiusd_exit0();
661 		}
662 
663 		req = request_create(frq.type, frq.fd,
664 				     &frq.srv_addr, &frq.clt_addr,
665 				     data, frq.size);
666 
667 		req->status = RS_COMPLETED;
668 		rc = request_handle(req, request_respond);
669 
670 		/* Inform the master */
671 		GRAD_DEBUG(1, "notifying the master");
672 		repl.code = RPP_COMPLETE;
673 		repl.size = 0;
674 		rpp_fd_write(rpp_stdout, &repl, sizeof repl, NULL);
675 		if (rc)
676 			request_free(req);
677 	}
678 	return 0;
679 }
680 
681 /* Master: Read notification from the child and update the request queue */
682 int
rpp_input_handler(int fd,void * data)683 rpp_input_handler(int fd, void *data)
684 {
685 	struct rpp_reply repl;
686 	rpp_proc_t *p = rpp_lookup_fd(fd);
687 	struct timeval tv, *tvp;
688 	int sz;
689 
690 	grad_insist(p != NULL);
691 
692 	if (radiusd_read_timeout) {
693 		tv.tv_sec = radiusd_read_timeout;
694 		tv.tv_usec = 0;
695 		tvp = &tv;
696 	} else
697 		tvp = NULL;
698 
699 	sz = rpp_fd_read(fd, &repl, sizeof(repl), tvp);
700 	if (sz == sizeof(repl)) {
701 		void *data = NULL;
702 
703 		if (repl.size) {
704 			data = grad_emalloc(repl.size);
705 			if (rpp_fd_read(fd, data, repl.size, tvp)
706 			    != repl.size) {
707 				_rpp_slay(p, _("error reading data"));
708 				grad_free(data);
709 				return 1;
710 			}
711 		}
712 
713 		if (p) {
714 		        GRAD_DEBUG1(1, "updating pid %d", p->pid);
715 			p->status = process_ready;
716 			request_update(p->pid, RS_COMPLETED, data);
717 		}
718 		grad_free(data);
719 	} else if (sz != 0) {
720 		_rpp_slay(p, _("error reading data; wrong data size returned"));
721 		return 1;
722 	}
723 
724 	return 0;
725 }
726 
727 /* Client: Send an update to the master */
728 int
rpp_update(void * data,size_t size)729 rpp_update(void *data, size_t size)
730 {
731 	struct rpp_reply repl;
732 
733 	repl.code = RPP_UPDATE;
734 	repl.size = size;
735 	rpp_fd_write(rpp_stdout, &repl, sizeof repl, NULL);
736 	rpp_fd_write(rpp_stdout, data, size, NULL);
737 	return 0;
738 }
739 
740 int
rpp_input_close(int fd,void * data)741 rpp_input_close(int fd, void *data)
742 {
743 	rpp_proc_t *p = rpp_lookup_fd(fd);
744 	if (p)
745 		_rpp_remove(p);
746 	return 0;
747 }
748 
749 
750 
751 /* Don't use it. It's a debugging hook */
752 int
wd()753 wd()
754 {
755 	int volatile _st=0;
756 	while (!_st)
757 		_st=_st;
758 }
759