f5dda116800b8ffdfa99f433767718405caacbc8
[kai/samba.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 2 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, write to the Free Software
22    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25 #include "includes.h"
26 #include "lib/events/events.h"
27 #include "lib/tdb/include/tdb.h"
28 #include "lib/socket/socket.h"
29 #include "smbd/process_model.h"
30
31 /* For specifiying event context to GSSAPI below */
32 #include "system/kerberos.h"
33 #include "heimdal/lib/gssapi/gssapi_locl.h"
34
35 #include "passdb/secrets.h"
36
37 #ifdef HAVE_SETPROCTITLE
38 #ifdef HAVE_SETPROCTITLE_H
39 #include <setproctitle.h>
40 #endif
41 #else
42 static int setproctitle(const char *fmt, ...) PRINTF_ATTRIBUTE(1, 2);
43 static int setproctitle(const char *fmt, ...)
44 {
45         return 0;
46 }
47 #endif
48
49 /*
50   called when the process model is selected
51 */
52 static void standard_model_init(struct event_context *ev)
53 {
54         signal(SIGCHLD, SIG_IGN);
55 }
56
57 /*
58   called when a listening socket becomes readable. 
59 */
60 static void standard_accept_connection(struct event_context *ev, 
61                                        struct socket_context *sock, 
62                                        void (*new_conn)(struct event_context *, struct socket_context *, 
63                                                         uint32_t , void *), 
64                                        void *private)
65 {
66         NTSTATUS status;
67         struct socket_context *sock2;
68         pid_t pid;
69         struct event_context *ev2;
70         struct socket_address *c, *s;
71
72         /* accept an incoming connection. */
73         status = socket_accept(sock, &sock2);
74         if (!NT_STATUS_IS_OK(status)) {
75                 DEBUG(0,("standard_accept_connection: accept: %s\n",
76                          nt_errstr(status)));
77                 /* this looks strange, but is correct. We need to throttle things until
78                    the system clears enough resources to handle this new socket */
79                 sleep(1);
80                 return;
81         }
82
83         pid = fork();
84
85         if (pid != 0) {
86                 /* parent or error code ... */
87                 talloc_free(sock2);
88                 /* go back to the event loop */
89                 return;
90         }
91
92         pid = getpid();
93
94         /* This is now the child code. We need a completely new event_context to work with */
95         ev2 = event_context_init(NULL);
96
97         /* the service has given us a private pointer that
98            encapsulates the context it needs for this new connection -
99            everything else will be freed */
100         talloc_steal(ev2, private);
101         talloc_steal(private, sock2);
102
103         /* this will free all the listening sockets and all state that
104            is not associated with this new connection */
105         talloc_free(sock);
106         talloc_free(ev);
107
108         /* we don't care if the dup fails, as its only a select()
109            speed optimisation */
110         socket_dup(sock2);
111                         
112         /* tdb needs special fork handling */
113         if (tdb_reopen_all(1) == -1) {
114                 DEBUG(0,("standard_accept_connection: tdb_reopen_all failed.\n"));
115         }
116
117         /* Hack to ensure that GSSAPI uses the right event context */
118         gssapi_krb5_init_ev(ev2);
119
120         /* Ensure that the forked children do not expose identical random streams */
121         set_need_random_reseed();
122
123         /* setup the process title */
124         c = socket_get_peer_addr(sock2, ev2);
125         s = socket_get_my_addr(sock2, ev2);
126         if (s && c) {
127                 setproctitle("conn c[%s:%u] s[%s:%u] server_id[%d]",
128                              c->addr, c->port, s->addr, s->port, pid);
129         }
130         talloc_free(c);
131         talloc_free(s);
132
133         /* setup this new connection */
134         new_conn(ev2, sock2, pid, private);
135
136         /* we can't return to the top level here, as that event context is gone,
137            so we now process events in the new event context until there are no
138            more to process */      
139         event_loop_wait(ev2);
140
141         talloc_free(ev2);
142         exit(0);
143 }
144
145 /*
146   called to create a new server task
147 */
148 static void standard_new_task(struct event_context *ev, 
149                               void (*new_task)(struct event_context *, uint32_t , void *), 
150                               void *private)
151 {
152         pid_t pid;
153         struct event_context *ev2;
154
155         pid = fork();
156
157         if (pid != 0) {
158                 /* parent or error code ... go back to the event loop */
159                 return;
160         }
161
162         pid = getpid();
163
164         /* This is now the child code. We need a completely new event_context to work with */
165         ev2 = event_context_init(NULL);
166
167         /* the service has given us a private pointer that
168            encapsulates the context it needs for this new connection -
169            everything else will be freed */
170         talloc_steal(ev2, private);
171
172         /* this will free all the listening sockets and all state that
173            is not associated with this new connection */
174         talloc_free(ev);
175
176         /* tdb needs special fork handling */
177         if (tdb_reopen_all(1) == -1) {
178                 DEBUG(0,("standard_accept_connection: tdb_reopen_all failed.\n"));
179         }
180
181         /* Ensure that the forked children do not expose identical random streams */
182         set_need_random_reseed();
183
184         setproctitle("task server_id[%d]", pid);
185
186         /* setup this new connection */
187         new_task(ev2, pid, private);
188
189         /* we can't return to the top level here, as that event context is gone,
190            so we now process events in the new event context until there are no
191            more to process */      
192         event_loop_wait(ev2);
193
194         talloc_free(ev2);
195         exit(0);
196 }
197
198
199 /* called when a task goes down */
200 static void standard_terminate(struct event_context *ev, const char *reason) 
201 {
202         DEBUG(2,("standard_terminate: reason[%s]\n",reason));
203
204         /* this init_iconv() has the effect of freeing the iconv context memory,
205            which makes leak checking easier */
206         init_iconv();
207
208         /* the secrets db should really hang off the connection structure */
209         secrets_shutdown();
210
211         talloc_free(ev);
212
213         /* terminate this process */
214         exit(0);
215 }
216
217 /* called to set a title of a task or connection */
218 static void standard_set_title(struct event_context *ev, const char *title) 
219 {
220         if (title) {
221                 setproctitle("%s", title);
222         } else {
223                 setproctitle(NULL);
224         }
225 }
226
227 static const struct model_ops standard_ops = {
228         .name                   = "standard",
229         .model_init             = standard_model_init,
230         .accept_connection      = standard_accept_connection,
231         .new_task               = standard_new_task,
232         .terminate              = standard_terminate,
233         .set_title              = standard_set_title,
234 };
235
236 /*
237   initialise the standard process model, registering ourselves with the process model subsystem
238  */
239 NTSTATUS process_model_standard_init(void)
240 {
241         return register_process_model(&standard_ops);
242 }