1 /*
2  * ProFTPD - FTP server daemon
3  * Copyright (c) 2004-2016 The ProFTPD Project team
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
18  *
19  * As a special exemption, The ProFTPD Project team and other respective
20  * copyright holders give permission to link this program with OpenSSL, and
21  * distribute the resulting executable, without including the source code for
22  * OpenSSL in the source distribution.
23  */
24 
25 /* Children management code */
26 
27 #include "conf.h"
28 
29 static pool *child_pool = NULL;
30 static xaset_t *child_list = NULL;
31 static unsigned long child_listlen = 0;
32 
child_add(pid_t pid,int fd)33 int child_add(pid_t pid, int fd) {
34   pool *p;
35   pr_child_t *ch;
36 
37   /* If no child-tracking list has been allocated, create one. */
38   if (!child_pool) {
39     child_pool = make_sub_pool(permanent_pool);
40     pr_pool_tag(child_pool, "Child Pool");
41   }
42 
43   if (child_list == NULL) {
44     pool *list_pool;
45 
46     list_pool = make_sub_pool(child_pool);
47     pr_pool_tag(list_pool, "Child List Pool");
48 
49     child_list = xaset_create(list_pool, NULL);
50   }
51 
52   p = make_sub_pool(child_pool);
53   pr_pool_tag(p, "child session pool");
54 
55   ch = pcalloc(p, sizeof(pr_child_t));
56   ch->ch_pool = p;
57   ch->ch_pid = pid;
58   time(&ch->ch_when);
59   ch->ch_pipefd = fd;
60   ch->ch_dead = FALSE;
61 
62   xaset_insert(child_list, (xasetmember_t *) ch);
63   child_listlen++;
64 
65   return 0;
66 }
67 
child_count(void)68 unsigned long child_count(void) {
69   return child_listlen;
70 }
71 
child_get(pr_child_t * ch)72 pr_child_t *child_get(pr_child_t *ch) {
73   if (ch == NULL) {
74     return (pr_child_t *) child_list->xas_list;
75   }
76 
77   return ch->next;
78 }
79 
child_remove(pid_t pid)80 int child_remove(pid_t pid) {
81   pr_child_t *ch;
82 
83   if (!child_list) {
84     errno = EPERM;
85     return -1;
86   }
87 
88   for (ch = (pr_child_t *) child_list->xas_list; ch; ch = ch->next) {
89     if (ch->ch_pid == pid) {
90       ch->ch_dead = TRUE;
91       child_listlen--;
92       return 0;
93     }
94   }
95 
96   errno = ENOENT;
97   return -1;
98 }
99 
child_signal(int signo)100 void child_signal(int signo) {
101   pr_child_t *ch;
102 
103   if (child_list == NULL) {
104     return;
105   }
106 
107   for (ch = (pr_child_t *) child_list->xas_list; ch; ch = ch->next) {
108     if (kill(ch->ch_pid, signo) < 0) {
109       pr_trace_msg("signal", 1, "error sending signal %d to PID %lu: %s",
110         signo, (unsigned long) ch->ch_pid, strerror(errno));
111     }
112   }
113 
114   return;
115 }
116 
child_update(void)117 void child_update(void) {
118   pr_child_t *ch, *chn = NULL;
119 
120   if (child_list == NULL) {
121     return;
122   }
123 
124   /* Scan the child list, removing those entries marked as 'dead'. */
125   for (ch = (pr_child_t *) child_list->xas_list; ch; ch = chn) {
126     chn = ch->next;
127 
128     if (ch->ch_dead) {
129       if (ch->ch_pipefd != -1) {
130         (void) close(ch->ch_pipefd);
131       }
132 
133       xaset_remove(child_list, (xasetmember_t *) ch);
134       destroy_pool(ch->ch_pool);
135     }
136   }
137 
138   /* If the child list is empty, recover the list pool memory. */
139   if (child_list->xas_list == NULL) {
140     destroy_pool(child_list->pool);
141     child_list = NULL;
142     child_listlen = 0;
143   }
144 
145   return;
146 }
147