CVE-2020-25719 mit_samba: Create the talloc context earlier
[Samba.git] / source3 / lib / server_prefork_util.c
blob3e14015c81ee320c0f65cb680da4163d3826b5a6
1 /*
2 Unix SMB/Netbios implementation.
3 Prefork Helpers
4 Copyright (C) Simo Sorce <idra@samba.org> 2011
6 This program 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.
11 This program 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.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "includes.h"
21 #include "lib/server_prefork.h"
22 #include "lib/server_prefork_util.h"
24 void pfh_daemon_config(const char *daemon_name,
25 struct pf_daemon_config *cfg,
26 struct pf_daemon_config *default_cfg)
28 int min, max, rate, allow, life;
30 min = lp_parm_int(GLOBAL_SECTION_SNUM,
31 daemon_name,
32 "prefork_min_children",
33 default_cfg->min_children);
34 max = lp_parm_int(GLOBAL_SECTION_SNUM,
35 daemon_name,
36 "prefork_max_children",
37 default_cfg->max_children);
38 rate = lp_parm_int(GLOBAL_SECTION_SNUM,
39 daemon_name,
40 "prefork_spawn_rate",
41 default_cfg->spawn_rate);
42 allow = lp_parm_int(GLOBAL_SECTION_SNUM,
43 daemon_name,
44 "prefork_max_allowed_clients",
45 default_cfg->max_allowed_clients);
46 life = lp_parm_int(GLOBAL_SECTION_SNUM,
47 daemon_name,
48 "prefork_child_min_life",
49 default_cfg->child_min_life);
51 if (max > cfg->max_children && cfg->max_children != 0) {
52 cfg->prefork_status |= PFH_NEW_MAX;
55 cfg->min_children = min;
56 cfg->max_children = max;
57 cfg->spawn_rate = rate;
58 cfg->max_allowed_clients = allow;
59 cfg->child_min_life = life;
62 void pfh_manage_pool(struct tevent_context *ev_ctx,
63 struct messaging_context *msg_ctx,
64 struct pf_daemon_config *cfg,
65 struct prefork_pool *pool)
67 time_t now = time(NULL);
68 int total, avail;
69 int ret, n;
70 bool msg = false;
72 if ((cfg->prefork_status & PFH_NEW_MAX) &&
73 !(cfg->prefork_status & PFH_ENOSPC)) {
74 ret = prefork_expand_pool(pool, cfg->max_children);
75 if (ret == ENOSPC) {
76 cfg->prefork_status |= PFH_ENOSPC;
78 cfg->prefork_status &= ~PFH_NEW_MAX;
81 total = prefork_count_children(pool, NULL);
82 avail = prefork_count_allowed_connections(pool);
83 DEBUG(10, ("(Pre)Stats: children: %d, allowed connections: %d\n",
84 total, avail));
86 if ((total < cfg->max_children) && (avail < cfg->spawn_rate)) {
87 n = prefork_add_children(ev_ctx, msg_ctx,
88 pool, cfg->spawn_rate);
89 if (n < cfg->spawn_rate) {
90 DEBUG(10, ("Attempted to add %d children but only "
91 "%d were actually added!\n",
92 cfg->spawn_rate, n));
94 } else if ((avail - cfg->min_children) >= cfg->spawn_rate) {
95 /* be a little slower in retiring children, to allow for
96 * double spikes of traffic to be handled more gracefully */
97 n = (cfg->spawn_rate / 2) + 1;
98 if (n > cfg->spawn_rate) {
99 n = cfg->spawn_rate;
101 if ((total - n) < cfg->min_children) {
102 n = total - cfg->min_children;
104 if (n >= 0) {
105 prefork_retire_children(msg_ctx, pool, n,
106 now - cfg->child_min_life);
110 /* total/avail may have just been changed in the above if/else */
111 total = prefork_count_children(pool, NULL);
112 avail = prefork_count_allowed_connections(pool);
113 if ((total == cfg->max_children) && (avail < cfg->spawn_rate)) {
114 n = avail;
115 while (avail < cfg->spawn_rate) {
116 prefork_increase_allowed_clients(pool,
117 cfg->max_allowed_clients);
118 avail = prefork_count_allowed_connections(pool);
119 /* if avail didn't change do not loop forever */
120 if (n == avail) break;
121 n = avail;
123 msg = true;
124 } else if (avail > total + cfg->spawn_rate) {
125 n = avail;
126 while (avail > total + cfg->spawn_rate) {
127 prefork_decrease_allowed_clients(pool);
128 avail = prefork_count_allowed_connections(pool);
129 /* if avail didn't change do not loop forever */
130 if (n == avail) break;
131 n = avail;
135 /* send message to all children when we change maximum allowed
136 * connections, so that they can decide to start again to listen to
137 * sockets if they were already topping the number of allowed
138 * clients. Useful only when we increase allowed clients */
139 if (msg) {
140 prefork_warn_active_children(msg_ctx, pool);
143 DEBUG(10, ("Stats: children: %d, allowed connections: %d\n",
144 prefork_count_children(pool, NULL),
145 prefork_count_allowed_connections(pool)));
148 void pfh_client_terminated(struct pf_worker_data *pf)
150 if (pf->num_clients >= 0) {
151 pf->num_clients--;
152 } else {
153 if (pf->status != PF_WORKER_EXITING) {
154 DEBUG(1, ("Invalid num clients, stopping!\n"));
156 pf->status = PF_WORKER_EXITING;
157 pf->num_clients = -1;
161 bool pfh_child_allowed_to_accept(struct pf_worker_data *pf)
163 if (pf->status == PF_WORKER_EXITING ||
164 pf->status == PF_WORKER_ACCEPTING) {
165 return false;
168 return (pf->num_clients < pf->allowed_clients);