5439e5235a52d1ae6f798ee97b5bd0f272fb7450
[kai/samba.git] / source / 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 "dlinklist.h"
29 #include "smb_server/smb_server.h"
30
31 /*
32   called when the process model is selected
33 */
34 static void standard_model_init(struct event_context *ev)
35 {
36         signal(SIGCHLD, SIG_IGN);
37 }
38
39 /*
40   called when a listening socket becomes readable. 
41 */
42 static void standard_accept_connection(struct event_context *ev, 
43                                        struct socket_context *sock, 
44                                        void (*new_conn)(struct event_context *, struct socket_context *, 
45                                                         uint32_t , void *), 
46                                        void *private)
47 {
48         NTSTATUS status;
49         struct socket_context *sock2;
50         pid_t pid;
51         struct event_context *ev2;
52
53         /* accept an incoming connection. */
54         status = socket_accept(sock, &sock2);
55         if (!NT_STATUS_IS_OK(status)) {
56                 DEBUG(0,("standard_accept_connection: accept: %s\n",
57                          nt_errstr(status)));
58                 return;
59         }
60
61         pid = fork();
62
63         if (pid != 0) {
64                 /* parent or error code ... */
65                 talloc_free(sock2);
66                 /* go back to the event loop */
67                 return;
68         }
69
70         /* This is now the child code. We need a completely new event_context to work with */
71         ev2 = event_context_init(NULL);
72
73         /* the service has given us a private pointer that
74            encapsulates the context it needs for this new connection -
75            everything else will be freed */
76         talloc_steal(ev2, private);
77         talloc_steal(private, sock2);
78
79         /* this will free all the listening sockets and all state that
80            is not associated with this new connection */
81         talloc_free(sock);
82         talloc_free(ev);
83
84         /* we don't care if the dup fails, as its only a select()
85            speed optimisation */
86         socket_dup(sock2);
87                         
88         /* tdb needs special fork handling */
89         if (tdb_reopen_all() == -1) {
90                 DEBUG(0,("standard_accept_connection: tdb_reopen_all failed.\n"));
91         }
92
93         /* Ensure that the forked children do not expose identical random streams */
94         set_need_random_reseed();
95
96         /* setup this new connection */
97         new_conn(ev2, sock2, getpid(), private);
98
99         /* we can't return to the top level here, as that event context is gone,
100            so we now process events in the new event context until there are no
101            more to process */      
102         event_loop_wait(ev2);
103
104         talloc_free(ev2);
105         exit(0);
106 }
107
108 /*
109   called to create a new server task
110 */
111 static void standard_new_task(struct event_context *ev, 
112                               void (*new_task)(struct event_context *, uint32_t , void *), 
113                               void *private)
114 {
115         pid_t pid;
116         struct event_context *ev2;
117
118         pid = fork();
119
120         if (pid != 0) {
121                 /* parent or error code ... go back to the event loop */
122                 return;
123         }
124
125         /* This is now the child code. We need a completely new event_context to work with */
126         ev2 = event_context_init(NULL);
127
128         /* the service has given us a private pointer that
129            encapsulates the context it needs for this new connection -
130            everything else will be freed */
131         talloc_steal(ev2, private);
132
133         /* this will free all the listening sockets and all state that
134            is not associated with this new connection */
135         talloc_free(ev);
136
137         /* tdb needs special fork handling */
138         if (tdb_reopen_all() == -1) {
139                 DEBUG(0,("standard_accept_connection: tdb_reopen_all failed.\n"));
140         }
141
142         /* Ensure that the forked children do not expose identical random streams */
143         set_need_random_reseed();
144
145         /* setup this new connection */
146         new_task(ev2, getpid(), private);
147
148         /* we can't return to the top level here, as that event context is gone,
149            so we now process events in the new event context until there are no
150            more to process */      
151         event_loop_wait(ev2);
152
153         talloc_free(ev2);
154         exit(0);
155 }
156
157
158 /* called when a task goes down */
159 static void standard_terminate(struct event_context *ev, const char *reason) 
160 {
161         DEBUG(2,("standard_terminate: reason[%s]\n",reason));
162
163         /* this init_iconv() has the effect of freeing the iconv context memory,
164            which makes leak checking easier */
165         init_iconv();
166
167         /* the secrets db should really hang off the connection structure */
168         secrets_shutdown();
169
170         talloc_free(ev);
171
172         /* terminate this process */
173         exit(0);
174 }
175
176
177 static const struct model_ops standard_ops = {
178         .name                   = "standard",
179         .model_init             = standard_model_init,
180         .accept_connection      = standard_accept_connection,
181         .new_task               = standard_new_task,
182         .terminate              = standard_terminate,
183 };
184
185 /*
186   initialise the standard process model, registering ourselves with the process model subsystem
187  */
188 NTSTATUS process_model_standard_init(void)
189 {
190         return register_process_model(&standard_ops);
191 }