s4-server: call the ldb_wrap_fork_hook() after a fork()
[ira/wip.git] / source4 / smbd / process_standard.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    process model: standard (1 process per client connection)
5
6    Copyright (C) Andrew Tridgell 1992-2005
7    Copyright (C) James J Myers 2003 <myersjj@samba.org>
8    Copyright (C) Stefan (metze) Metzmacher 2004
9    
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 3 of the License, or
13    (at your option) any later version.
14    
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19    
20    You should have received a copy of the GNU General Public License
21    along with this program.  If not, see <http://www.gnu.org/licenses/>.
22 */
23
24 #include "includes.h"
25 #include "lib/events/events.h"
26 #include "../tdb/include/tdb.h"
27 #include "smbd/process_model.h"
28 #include "system/filesys.h"
29 #include "cluster/cluster.h"
30 #include "param/param.h"
31 #include "lib/ldb_wrap.h"
32
33 #ifdef HAVE_SETPROCTITLE
34 #ifdef HAVE_SETPROCTITLE_H
35 #include <setproctitle.h>
36 #endif
37 #else
38 #define setproctitle none_setproctitle
39 static int none_setproctitle(const char *fmt, ...) PRINTF_ATTRIBUTE(1, 2);
40 static int none_setproctitle(const char *fmt, ...)
41 {
42         return 0;
43 }
44 #endif
45
46 /* we hold a pipe open in the parent, and the any child
47    processes wait for EOF on that pipe. This ensures that
48    children die when the parent dies */
49 static int child_pipe[2];
50
51 /*
52   called when the process model is selected
53 */
54 static void standard_model_init(struct tevent_context *ev)
55 {
56         pipe(child_pipe);
57         signal(SIGCHLD, SIG_IGN);
58 }
59
60 /*
61   handle EOF on the child pipe
62 */
63 static void standard_pipe_handler(struct tevent_context *event_ctx, struct tevent_fd *fde, 
64                                   uint16_t flags, void *private_data)
65 {
66         DEBUG(10,("Child %d exiting\n", (int)getpid()));
67         exit(0);
68 }
69
70 /*
71   called when a listening socket becomes readable. 
72 */
73 static void standard_accept_connection(struct tevent_context *ev, 
74                                        struct loadparm_context *lp_ctx,
75                                        struct socket_context *sock, 
76                                        void (*new_conn)(struct tevent_context *,
77                                                         struct loadparm_context *, struct socket_context *, 
78                                                         struct server_id , void *), 
79                                        void *private_data)
80 {
81         NTSTATUS status;
82         struct socket_context *sock2;
83         pid_t pid;
84         struct tevent_context *ev2;
85         struct socket_address *c, *s;
86
87         /* accept an incoming connection. */
88         status = socket_accept(sock, &sock2);
89         if (!NT_STATUS_IS_OK(status)) {
90                 DEBUG(0,("standard_accept_connection: accept: %s\n",
91                          nt_errstr(status)));
92                 /* this looks strange, but is correct. We need to throttle things until
93                    the system clears enough resources to handle this new socket */
94                 sleep(1);
95                 return;
96         }
97
98         pid = fork();
99
100         if (pid != 0) {
101                 /* parent or error code ... */
102                 talloc_free(sock2);
103                 /* go back to the event loop */
104                 return;
105         }
106
107         pid = getpid();
108
109         /* This is now the child code. We need a completely new event_context to work with */
110         ev2 = s4_event_context_init(NULL);
111
112         /* the service has given us a private pointer that
113            encapsulates the context it needs for this new connection -
114            everything else will be freed */
115         talloc_steal(ev2, private_data);
116         talloc_steal(private_data, sock2);
117
118         /* this will free all the listening sockets and all state that
119            is not associated with this new connection */
120         talloc_free(sock);
121         talloc_free(ev);
122
123         /* we don't care if the dup fails, as its only a select()
124            speed optimisation */
125         socket_dup(sock2);
126                         
127         /* tdb needs special fork handling */
128         if (tdb_reopen_all(1) == -1) {
129                 DEBUG(0,("standard_accept_connection: tdb_reopen_all failed.\n"));
130         }
131         ldb_wrap_fork_hook();
132
133         tevent_add_fd(ev2, ev2, child_pipe[0], TEVENT_FD_READ,
134                       standard_pipe_handler, NULL);
135         close(child_pipe[1]);
136
137         /* Ensure that the forked children do not expose identical random streams */
138         set_need_random_reseed();
139
140         /* setup the process title */
141         c = socket_get_peer_addr(sock2, ev2);
142         s = socket_get_my_addr(sock2, ev2);
143         if (s && c) {
144                 setproctitle("conn c[%s:%u] s[%s:%u] server_id[%d]",
145                              c->addr, c->port, s->addr, s->port, pid);
146         }
147         talloc_free(c);
148         talloc_free(s);
149
150         /* setup this new connection.  Cluster ID is PID based for this process modal */
151         new_conn(ev2, lp_ctx, sock2, cluster_id(pid, 0), private_data);
152
153         /* we can't return to the top level here, as that event context is gone,
154            so we now process events in the new event context until there are no
155            more to process */      
156         event_loop_wait(ev2);
157
158         talloc_free(ev2);
159         exit(0);
160 }
161
162 /*
163   called to create a new server task
164 */
165 static void standard_new_task(struct tevent_context *ev, 
166                               struct loadparm_context *lp_ctx,
167                               const char *service_name,
168                               void (*new_task)(struct tevent_context *, struct loadparm_context *lp_ctx, struct server_id , void *), 
169                               void *private_data)
170 {
171         pid_t pid;
172         struct tevent_context *ev2;
173
174         pid = fork();
175
176         if (pid != 0) {
177                 /* parent or error code ... go back to the event loop */
178                 return;
179         }
180
181         pid = getpid();
182
183         /* This is now the child code. We need a completely new event_context to work with */
184         ev2 = s4_event_context_init(NULL);
185
186         /* the service has given us a private pointer that
187            encapsulates the context it needs for this new connection -
188            everything else will be freed */
189         talloc_steal(ev2, private_data);
190
191         /* this will free all the listening sockets and all state that
192            is not associated with this new connection */
193         talloc_free(ev);
194
195         /* tdb needs special fork handling */
196         if (tdb_reopen_all(1) == -1) {
197                 DEBUG(0,("standard_accept_connection: tdb_reopen_all failed.\n"));
198         }
199         ldb_wrap_fork_hook();
200
201         tevent_add_fd(ev2, ev2, child_pipe[0], TEVENT_FD_READ,
202                       standard_pipe_handler, NULL);
203         close(child_pipe[1]);
204
205         /* Ensure that the forked children do not expose identical random streams */
206         set_need_random_reseed();
207
208         setproctitle("task %s server_id[%d]", service_name, pid);
209
210         /* setup this new task.  Cluster ID is PID based for this process modal */
211         new_task(ev2, lp_ctx, cluster_id(pid, 0), private_data);
212
213         /* we can't return to the top level here, as that event context is gone,
214            so we now process events in the new event context until there are no
215            more to process */      
216         event_loop_wait(ev2);
217
218         talloc_free(ev2);
219         exit(0);
220 }
221
222
223 /* called when a task goes down */
224 _NORETURN_ static void standard_terminate(struct tevent_context *ev, struct loadparm_context *lp_ctx, 
225                                           const char *reason) 
226 {
227         DEBUG(2,("standard_terminate: reason[%s]\n",reason));
228
229         /* this reload_charcnv() has the effect of freeing the iconv context memory,
230            which makes leak checking easier */
231         reload_charcnv(lp_ctx);
232
233         talloc_free(ev);
234
235         /* terminate this process */
236         exit(0);
237 }
238
239 /* called to set a title of a task or connection */
240 static void standard_set_title(struct tevent_context *ev, const char *title) 
241 {
242         if (title) {
243                 setproctitle("%s", title);
244         } else {
245                 setproctitle(NULL);
246         }
247 }
248
249 static const struct model_ops standard_ops = {
250         .name                   = "standard",
251         .model_init             = standard_model_init,
252         .accept_connection      = standard_accept_connection,
253         .new_task               = standard_new_task,
254         .terminate              = standard_terminate,
255         .set_title              = standard_set_title,
256 };
257
258 /*
259   initialise the standard process model, registering ourselves with the process model subsystem
260  */
261 NTSTATUS process_model_standard_init(void)
262 {
263         return register_process_model(&standard_ops);
264 }