r2628: got rid of some warnings and converted a few more places to use hierarchical...
[garming/samba-autobuild/.git] / source4 / smbd / service.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    SERVER SERVICE code
5
6    Copyright (C) Andrew Tridgell 2003
7    Copyright (C) Stefan (metze) Metzmacher      2004
8    
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 2 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24 #include "includes.h"
25
26 struct server_context *server_service_startup(const char *model)
27 {
28         int i;
29         const char **server_services = lp_server_services();
30         TALLOC_CTX *mem_ctx;
31         struct server_context *srv_ctx;
32         const struct model_ops *model_ops;
33
34         if (!server_services) {
35                 DEBUG(0,("process_model_startup: no endpoint servers configured\n"));
36                 return NULL;
37         }
38
39         model_ops = process_model_startup(model);
40         if (!model_ops) {
41                 DEBUG(0,("process_model_startup('%s') failed\n", model));
42                 return NULL;
43         }
44
45         mem_ctx = talloc_init("server_context");
46         if (!mem_ctx) {
47                 DEBUG(0,("talloc_init(server_context) failed\n"));
48                 return NULL;
49         }
50
51         srv_ctx = talloc_p(mem_ctx, struct server_context);
52         if (!srv_ctx) {
53                 DEBUG(0,("talloc_p(mem_ctx, struct server_context) failed\n"));
54                 return NULL;    
55         }
56
57         ZERO_STRUCTP(srv_ctx);
58         srv_ctx->mem_ctx = mem_ctx;
59
60         srv_ctx->events = event_context_init();
61         if (!srv_ctx->events) {
62                 DEBUG(0,("event_context_init() failed\n"));
63                 return NULL;    
64         }
65
66
67         for (i=0;server_services[i];i++) {
68                 TALLOC_CTX *mem_ctx2;
69                 const struct server_service_ops *service_ops;
70                 struct server_service *service;
71
72                 service_ops = server_service_byname(server_services[i]);
73                 if (!service_ops) {
74                         DEBUG(0,("process_model_startup: failed to find server service = '%s'\n", server_services[i]));
75                         return NULL;
76                 }
77
78                 mem_ctx2 = talloc_init("server_service");
79
80                 service = talloc_p(mem_ctx2, struct server_service);
81                 if (!service) {
82                         DEBUG(0,("talloc_p(mem_ctx, struct server_service) failed\n"));
83                         return NULL;
84                 }
85
86                 ZERO_STRUCTP(service);
87                 service->mem_ctx        = mem_ctx2;
88                 service->ops            = service_ops;
89                 service->model_ops      = model_ops;
90                 service->srv_ctx        = srv_ctx;
91                 
92                 /* TODO: service_init() should return a result */
93                 service->ops->service_init(service, model_ops);
94         }
95
96         return srv_ctx;
97 }
98
99 /*
100   setup a listen stream socket
101   if you pass *port == 0, then a port > 1024 is used
102  */
103 struct server_socket *service_setup_socket(struct server_service *service,
104                                            const struct model_ops *model_ops,
105                                            const char *sock_addr,
106                                            uint16_t *port)
107 {
108         NTSTATUS status;
109         struct server_socket *srv_sock;
110         struct socket_context *socket_ctx;
111         struct fd_event fde;
112         int i;
113
114         if (*port == 0) {
115                 for (i=SERVER_TCP_LOW_PORT;i<= SERVER_TCP_HIGH_PORT;i++) {
116                         status = socket_create("ipv4", SOCKET_TYPE_STREAM, &socket_ctx, 0);
117                         if (NT_STATUS_IS_OK(status)) {
118                                 *port = i;
119                                 break;
120                         }
121                 }
122         } else {
123                 status = socket_create("ipv4", SOCKET_TYPE_STREAM, &socket_ctx, 0);
124         }
125
126         if (!NT_STATUS_IS_OK(status)) {
127                 DEBUG(0,("Failed to open socket on %s:%u - %s\n",
128                         sock_addr, *port, nt_errstr(status)));
129                 return NULL;
130         }
131
132         /* ready to listen */
133         status = socket_set_option(socket_ctx, "SO_KEEPALIVE SO_REUSEADDR=1", NULL);
134         if (!NT_STATUS_IS_OK(status)) {
135                 DEBUG(0,("socket_set_option(socket_ctx, SO_KEEPALIVE, NULL): %s\n",
136                         nt_errstr(status)));
137                 socket_destroy(socket_ctx);
138                 return NULL;
139         }
140         status = socket_set_option(socket_ctx, lp_socket_options(), NULL);
141         if (!NT_STATUS_IS_OK(status)) {
142                 DEBUG(0,("socket_set_option(socket_ctx, lp_socket_options(), NULL): %s\n",
143                         nt_errstr(status)));
144                 socket_destroy(socket_ctx);
145                 return NULL;
146         }
147
148         /* TODO: set socket ACL's here when they're implemented */
149
150         status = socket_listen(socket_ctx, sock_addr, *port, SERVER_LISTEN_BACKLOG, 0);
151         if (!NT_STATUS_IS_OK(status)) {
152                 DEBUG(0,("Failed to listen on %s:%u - %s\n",
153                         sock_addr, *port, nt_errstr(status)));
154                 socket_destroy(socket_ctx);
155                 return NULL;
156         }
157
158         srv_sock = talloc_p(service, struct server_socket);
159         if (!srv_sock) {
160                 DEBUG(0,("talloc_p(mem_ctx, struct server_socket) failed\n"));
161                 socket_destroy(socket_ctx);
162                 return NULL;
163         }
164
165         /* we are only interested in read events on the listen socket */
166         fde.fd          = socket_get_fd(socket_ctx);
167         fde.flags       = EVENT_FD_READ;
168         fde.private     = srv_sock;
169         fde.handler     = model_ops->accept_connection;
170
171         ZERO_STRUCTP(srv_sock);
172         srv_sock->mem_ctx       = srv_sock;
173         srv_sock->service       = service;
174         srv_sock->socket        = socket_ctx;
175         srv_sock->event.ctx     = service->srv_ctx->events;
176         srv_sock->event.fde     = event_add_fd(srv_sock->event.ctx, &fde);
177         if (!srv_sock->event.fde) {
178                 DEBUG(0,("event_add_fd(srv_sock->event.ctx, &fde) failed\n"));
179                 socket_destroy(socket_ctx);
180                 return NULL;
181         }
182
183         DLIST_ADD(service->socket_list, srv_sock);
184
185         return srv_sock;
186 }
187
188 struct server_connection *server_setup_connection(struct event_context *ev, 
189                                                   struct server_socket *server_socket, 
190                                                   struct socket_context *sock, 
191                                                   time_t t)
192 {
193         struct fd_event fde;
194         struct timed_event idle;
195         struct server_connection *srv_conn;
196
197         srv_conn = talloc_p(server_socket, struct server_connection);
198         if (!srv_conn) {
199                 DEBUG(0,("talloc_p(mem_ctx, struct server_service_connection) failed\n"));
200                 return NULL;
201         }
202
203         ZERO_STRUCTP(srv_conn);
204         srv_conn->mem_ctx = srv_conn;
205
206         fde.private     = srv_conn;
207         fde.fd          = socket_get_fd(sock);
208         fde.flags       = EVENT_FD_READ;
209         fde.handler     = server_io_handler;
210
211         idle.private    = srv_conn;
212         idle.next_event = t + SERVER_DEFAULT_IDLE_TIME;
213         idle.handler    = server_idle_handler;
214
215         srv_conn->event.ctx             = ev;
216         srv_conn->event.fde             = &fde;
217         srv_conn->event.idle            = &idle;
218         srv_conn->event.idle_time       = SERVER_DEFAULT_IDLE_TIME;
219
220         srv_conn->server_socket         = server_socket;
221         srv_conn->service               = server_socket->service;
222         srv_conn->socket                = sock;
223
224         /* create a smb server context and add it to out event
225            handling */
226         server_socket->service->ops->accept_connection(srv_conn);
227
228         /* accpect_connection() of the service may changed idle.next_event */
229         srv_conn->event.fde     = event_add_fd(ev,&fde);
230         srv_conn->event.idle    = event_add_timed(ev,&idle);
231
232         if (!socket_check_access(sock, "smbd", lp_hostsallow(-1), lp_hostsdeny(-1))) {
233                 server_terminate_connection(srv_conn, "denied by access rules");
234                 return NULL;
235         }
236
237         return srv_conn;
238 }
239
240 /*
241   close the socket and shutdown a server_context
242 */
243 void server_terminate_connection(struct server_connection *srv_conn, const char *reason)
244 {
245         DEBUG(2,("server_terminate_connection\n"));
246         srv_conn->service->model_ops->terminate_connection(srv_conn, reason);
247 }
248
249 void server_destroy_connection(struct server_connection *srv_conn)
250 {
251         socket_destroy(srv_conn->socket);
252
253         event_remove_fd(srv_conn->event.ctx, srv_conn->event.fde);
254         srv_conn->event.fde = NULL;
255         event_remove_timed(srv_conn->event.ctx, srv_conn->event.idle);
256         srv_conn->event.idle = NULL;
257
258         talloc_destroy(srv_conn->mem_ctx);
259 }
260
261 void server_io_handler(struct event_context *ev, struct fd_event *fde, time_t t, uint16_t flags)
262 {
263         struct server_connection *conn = fde->private;
264
265         conn->event.idle->next_event = t + conn->event.idle_time;
266
267         if (flags & EVENT_FD_WRITE) {
268                 conn->service->ops->send_handler(conn, t, flags);
269                 return;
270         }
271
272         if (flags & EVENT_FD_READ) {
273                 conn->service->ops->recv_handler(conn, t, flags);
274         }
275
276 }
277
278 void server_idle_handler(struct event_context *ev, struct timed_event *idle, time_t t)
279 {
280         struct server_connection *conn = idle->private;
281
282         conn->event.idle->next_event = t + conn->event.idle_time;
283
284         conn->service->ops->idle_handler(conn,t);
285 }
286 /*
287   return the operations structure for a named backend of the specified type
288 */
289 const struct server_service_ops *server_service_byname(const char *name)
290 {
291         if (strcmp("smb",name)==0) {
292                 return smbsrv_get_ops();
293         }
294         if (strcmp("rpc",name)==0) {
295                 return dcesrv_get_ops();
296         }
297         if (strcmp("ldap",name)==0) {
298                 return ldapsrv_get_ops();
299         }
300         return NULL;
301 }
302
303 static NTSTATUS register_server_service_ops(const void *_ops)
304 {
305         return NT_STATUS_NOT_IMPLEMENTED;
306 }
307
308 /*
309   initialise the SERVER SERVICE subsystem
310 */
311 BOOL server_service_init(void)
312 {
313         NTSTATUS status;
314
315         status = register_subsystem("service", register_server_service_ops); 
316         if (!NT_STATUS_IS_OK(status)) {
317                 return False;
318         }
319
320         /* FIXME: Perhaps panic if a basic endpoint server, such as EPMAPER, fails to initialise? */
321         static_init_server_service;
322
323         DEBUG(3,("SERVER SERVICE subsystem version %d initialised\n", SERVER_SERVICE_VERSION));
324         return True;
325 }