s4-libnet: Fix memory leak of lsa_RefDomainList and lsa_String onto libnet_ctx
[ambi/samba-autobuild/.git] / source4 / smbd / process_prefork.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    process model: prefork (n client connections per process)
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    Copyright (C) Andrew Bartlett 2008 <abartlet@samba.org>
10    Copyright (C) David Disseldorp 2008 <ddiss@sgi.com>
11    
12    This program is free software; you can redistribute it and/or modify
13    it under the terms of the GNU General Public License as published by
14    the Free Software Foundation; either version 3 of the License, or
15    (at your option) any later version.
16    
17    This program is distributed in the hope that it will be useful,
18    but WITHOUT ANY WARRANTY; without even the implied warranty of
19    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20    GNU General Public License for more details.
21    
22    You should have received a copy of the GNU General Public License
23    along with this program.  If not, see <http://www.gnu.org/licenses/>.
24 */
25
26 #include "includes.h"
27 #include "lib/events/events.h"
28 #include "lib/socket/socket.h"
29 #include "smbd/process_model.h"
30 #include "system/filesys.h"
31 #include "cluster/cluster.h"
32 #include "param/param.h"
33 #include "ldb_wrap.h"
34
35 #ifdef HAVE_SETPROCTITLE
36 #ifdef HAVE_SETPROCTITLE_H
37 #include <setproctitle.h>
38 #endif
39 #else
40 #define setproctitle none_setproctitle
41 static int none_setproctitle(const char *fmt, ...) PRINTF_ATTRIBUTE(1, 2);
42 static int none_setproctitle(const char *fmt, ...)
43 {
44         return 0;
45 }
46 #endif
47
48 NTSTATUS process_model_prefork_init(void);
49
50 /*
51   called when the process model is selected
52 */
53 static void prefork_model_init(void)
54 {
55         signal(SIGCHLD, SIG_IGN);
56 }
57
58 static void prefork_reload_after_fork(void)
59 {
60         ldb_wrap_fork_hook();
61
62         /* Ensure that the forked children do not expose identical random streams */
63         set_need_random_reseed();
64 }
65
66 /*
67   called when a listening socket becomes readable. 
68 */
69 static void prefork_accept_connection(struct tevent_context *ev, 
70                                       struct loadparm_context *lp_ctx,
71                                       struct socket_context *listen_socket,
72                                        void (*new_conn)(struct tevent_context *,
73                                                         struct loadparm_context *, struct socket_context *, 
74                                                         struct server_id , void *), 
75                                        void *private_data)
76 {
77         NTSTATUS status;
78         struct socket_context *connected_socket;
79         pid_t pid = getpid();
80
81         /* accept an incoming connection. */
82         status = socket_accept(listen_socket, &connected_socket);
83         if (!NT_STATUS_IS_OK(status)) {
84                 return;
85         }
86
87         talloc_steal(private_data, connected_socket);
88
89         new_conn(ev, lp_ctx, connected_socket, cluster_id(pid, socket_get_fd(connected_socket)), private_data);
90 }
91
92 /*
93   called to create a new server task
94 */
95 static void prefork_new_task(struct tevent_context *ev, 
96                              struct loadparm_context *lp_ctx,
97                              const char *service_name,
98                              void (*new_task_fn)(struct tevent_context *, struct loadparm_context *lp_ctx, struct server_id , void *),
99                              void *private_data)
100 {
101         pid_t pid;
102         int i, num_children;
103
104         struct tevent_context *ev2, *ev_parent;
105
106         pid = fork();
107
108         if (pid != 0) {
109                 /* parent or error code ... go back to the event loop */
110                 return;
111         }
112
113         pid = getpid();
114
115         /* This is now the child code. We need a completely new event_context to work with */
116         ev2 = s4_event_context_init(NULL);
117
118         /* the service has given us a private pointer that
119            encapsulates the context it needs for this new connection -
120            everything else will be freed */
121         talloc_steal(ev2, private_data);
122
123         /* this will free all the listening sockets and all state that
124            is not associated with this new connection */
125         talloc_free(ev);
126
127         setproctitle("task %s server_id[%d]", service_name, (int)pid);
128
129         prefork_reload_after_fork();
130
131         /* setup this new connection: process will bind to it's sockets etc */
132         new_task_fn(ev2, lp_ctx, cluster_id(pid, 0), private_data);
133
134         num_children = lpcfg_parm_int(lp_ctx, NULL, "prefork children", service_name, 0);
135         if (num_children == 0) {
136
137                 /* We don't want any kids hanging around for this one,
138                  * let the parent do all the work */
139                 tevent_loop_wait(ev2);
140                 
141                 talloc_free(ev2);
142                 exit(0);
143         }
144
145         /* We are now free to spawn some child proccesses */
146
147         for (i=0; i < num_children; i++) {
148
149                 pid = fork();
150                 if (pid > 0) {
151                         continue;
152                 } else if (pid == -1) {
153                         return;
154                 } else {
155                         pid = getpid();
156                         setproctitle("task %s server_id[%d]", service_name, (int)pid);
157
158                         prefork_reload_after_fork();
159
160                         /* we can't return to the top level here, as that event context is gone,
161                            so we now process events in the new event context until there are no
162                            more to process */      
163                         tevent_loop_wait(ev2);
164                         
165                         talloc_free(ev2);
166                         exit(0);
167                 }
168         }
169
170         /* Don't listen on the sockets we just gave to the children */
171         talloc_free(ev2);
172         
173         /* But we need a events system to handle reaping children */
174         ev_parent = s4_event_context_init(NULL);
175
176         /* TODO: Handle some events... */
177         
178         /* we can't return to the top level here, as that event context is gone,
179            so we now process events in the new event context until there are no
180            more to process */      
181         tevent_loop_wait(ev_parent);
182         
183         talloc_free(ev_parent);
184         exit(0);
185
186 }
187
188
189 /* called when a task goes down */
190 static void prefork_terminate(struct tevent_context *ev, struct loadparm_context *lp_ctx, const char *reason)
191 {
192         DEBUG(2,("prefork_terminate: reason[%s]\n",reason));
193 }
194
195 /* called to set a title of a task or connection */
196 static void prefork_set_title(struct tevent_context *ev, const char *title) 
197 {
198         if (title) {
199                 setproctitle("%s", title);
200         } else {
201                 setproctitle(NULL);
202         }
203 }
204
205 static const struct model_ops prefork_ops = {
206         .name                   = "prefork",
207         .model_init             = prefork_model_init,
208         .accept_connection      = prefork_accept_connection,
209         .new_task               = prefork_new_task,
210         .terminate              = prefork_terminate,
211         .set_title              = prefork_set_title,
212 };
213
214 /*
215   initialise the prefork process model, registering ourselves with the process model subsystem
216  */
217 NTSTATUS process_model_prefork_init(void)
218 {
219         return register_process_model(&prefork_ops);
220 }