r2920: Support passing a handle to a SAMR pipe to a RPC Binding or Select
[samba.git] / source / 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         struct server_context *srv_ctx;
31         const struct model_ops *model_ops;
32
33         if (!server_services) {
34                 DEBUG(0,("process_model_startup: no endpoint servers configured\n"));
35                 return NULL;
36         }
37
38         model_ops = process_model_startup(model);
39         if (!model_ops) {
40                 DEBUG(0,("process_model_startup('%s') failed\n", model));
41                 return NULL;
42         }
43
44         srv_ctx = talloc_p(NULL, struct server_context);
45         if (!srv_ctx) {
46                 return NULL;    
47         }
48
49         ZERO_STRUCTP(srv_ctx);
50
51         srv_ctx->events = event_context_init();
52         if (!srv_ctx->events) {
53                 DEBUG(0,("event_context_init() failed\n"));
54                 return NULL;    
55         }
56
57
58         for (i=0;server_services[i];i++) {
59                 const struct server_service_ops *service_ops;
60                 struct server_service *service;
61
62                 service_ops = server_service_byname(server_services[i]);
63                 if (!service_ops) {
64                         DEBUG(0,("process_model_startup: failed to find server service = '%s'\n", server_services[i]));
65                         return NULL;
66                 }
67
68                 service = talloc_p(srv_ctx, struct server_service);
69                 if (!service) {
70                         return NULL;
71                 }
72
73                 ZERO_STRUCTP(service);
74                 service->ops            = service_ops;
75                 service->model_ops      = model_ops;
76                 service->srv_ctx        = srv_ctx;
77                 
78                 /* TODO: service_init() should return a result */
79                 service->ops->service_init(service, model_ops);
80         }
81
82         return srv_ctx;
83 }
84
85 /*
86   setup a listen stream socket
87   if you pass *port == 0, then a port > 1024 is used
88  */
89 struct server_socket *service_setup_socket(struct server_service *service,
90                                            const struct model_ops *model_ops,
91                                            const char *sock_addr,
92                                            uint16_t *port)
93 {
94         NTSTATUS status;
95         struct server_socket *srv_sock;
96         struct socket_context *socket_ctx;
97         struct fd_event fde;
98         int i;
99
100         status = socket_create("ipv4", SOCKET_TYPE_STREAM, &socket_ctx, 0);
101         if (!NT_STATUS_IS_OK(status)) {
102                 DEBUG(0,("Failed to open socket on %s:%u - %s\n",
103                         sock_addr, *port, nt_errstr(status)));
104                 return NULL;
105         }
106
107         talloc_steal(service, socket_ctx);
108
109         /* ready to listen */
110         status = socket_set_option(socket_ctx, "SO_KEEPALIVE SO_REUSEADDR=1", NULL);
111         if (!NT_STATUS_IS_OK(status)) {
112                 DEBUG(0,("socket_set_option(socket_ctx, SO_KEEPALIVE, NULL): %s\n",
113                         nt_errstr(status)));
114                 socket_destroy(socket_ctx);
115                 return NULL;
116         }
117         status = socket_set_option(socket_ctx, lp_socket_options(), NULL);
118         if (!NT_STATUS_IS_OK(status)) {
119                 DEBUG(0,("socket_set_option(socket_ctx, lp_socket_options(), NULL): %s\n",
120                         nt_errstr(status)));
121                 socket_destroy(socket_ctx);
122                 return NULL;
123         }
124
125         /* TODO: set socket ACL's here when they're implemented */
126
127         if (*port == 0) {
128                 for (i=SERVER_TCP_LOW_PORT;i<= SERVER_TCP_HIGH_PORT;i++) {
129                         status = socket_listen(socket_ctx, sock_addr, i, SERVER_LISTEN_BACKLOG, 0);
130                         if (NT_STATUS_IS_OK(status)) {
131                                 *port = i;
132                                 break;
133                         }
134                 }
135         } else {
136                 status = socket_listen(socket_ctx, sock_addr, *port, SERVER_LISTEN_BACKLOG, 0);
137         }
138
139         if (!NT_STATUS_IS_OK(status)) {
140                 DEBUG(0,("Failed to listen on %s:%u - %s\n",
141                         sock_addr, *port, nt_errstr(status)));
142                 socket_destroy(socket_ctx);
143                 return NULL;
144         }
145
146         srv_sock = talloc_p(service, struct server_socket);
147         if (!srv_sock) {
148                 DEBUG(0,("talloc_p(mem_ctx, struct server_socket) failed\n"));
149                 socket_destroy(socket_ctx);
150                 return NULL;
151         }
152
153         /* we are only interested in read events on the listen socket */
154         fde.fd          = socket_get_fd(socket_ctx);
155         fde.flags       = EVENT_FD_READ;
156         fde.private     = srv_sock;
157         fde.handler     = model_ops->accept_connection;
158
159         ZERO_STRUCTP(srv_sock);
160         srv_sock->service       = service;
161         srv_sock->socket        = socket_ctx;
162         srv_sock->event.ctx     = service->srv_ctx->events;
163         srv_sock->event.fde     = event_add_fd(srv_sock->event.ctx, &fde);
164         if (!srv_sock->event.fde) {
165                 DEBUG(0,("event_add_fd(srv_sock->event.ctx, &fde) failed\n"));
166                 socket_destroy(socket_ctx);
167                 return NULL;
168         }
169
170         DLIST_ADD(service->socket_list, srv_sock);
171
172         return srv_sock;
173 }
174
175 /*
176   destructor that handles necessary event context changes
177  */
178 static int server_destructor(void *ptr)
179 {
180         struct server_connection *conn = ptr;
181
182         if (conn->service) {
183                 conn->service->ops->close_connection(conn, "shutdown");
184         }
185
186         socket_destroy(conn->socket);
187
188         event_remove_fd(conn->event.ctx, conn->event.fde);
189         conn->event.fde = NULL;
190         event_remove_timed(conn->event.ctx, conn->event.idle);
191         conn->event.idle = NULL;
192
193         DLIST_REMOVE(conn->server_socket->connection_list, conn);
194
195         return 0;
196 }
197
198 struct server_connection *server_setup_connection(struct event_context *ev, 
199                                                   struct server_socket *server_socket, 
200                                                   struct socket_context *sock, 
201                                                   time_t t)
202 {
203         struct fd_event fde;
204         struct timed_event idle;
205         struct server_connection *srv_conn;
206
207         srv_conn = talloc_p(server_socket, struct server_connection);
208         if (!srv_conn) {
209                 DEBUG(0,("talloc_p(mem_ctx, struct server_service_connection) failed\n"));
210                 return NULL;
211         }
212
213         ZERO_STRUCTP(srv_conn);
214
215         fde.private     = srv_conn;
216         fde.fd          = socket_get_fd(sock);
217         fde.flags       = EVENT_FD_READ;
218         fde.handler     = server_io_handler;
219
220         idle.private    = srv_conn;
221         idle.next_event = t + SERVER_DEFAULT_IDLE_TIME;
222         idle.handler    = server_idle_handler;
223
224         srv_conn->event.ctx             = ev;
225         srv_conn->event.fde             = &fde;
226         srv_conn->event.idle            = &idle;
227         srv_conn->event.idle_time       = SERVER_DEFAULT_IDLE_TIME;
228
229         srv_conn->server_socket         = server_socket;
230         srv_conn->service               = server_socket->service;
231         srv_conn->socket                = sock;
232
233         /* create a smb server context and add it to out event
234            handling */
235         server_socket->service->ops->accept_connection(srv_conn);
236
237         /* accpect_connection() of the service may changed idle.next_event */
238         srv_conn->event.fde     = event_add_fd(ev,&fde);
239         srv_conn->event.idle    = event_add_timed(ev,&idle);
240
241         talloc_set_destructor(srv_conn, server_destructor);
242
243         if (!socket_check_access(sock, "smbd", lp_hostsallow(-1), lp_hostsdeny(-1))) {
244                 server_terminate_connection(srv_conn, "denied by access rules");
245                 return NULL;
246         }
247
248         return srv_conn;
249 }
250
251 /*
252   close the socket and shutdown a server_context
253 */
254 void server_terminate_connection(struct server_connection *srv_conn, const char *reason)
255 {
256         DEBUG(2,("server_terminate_connection\n"));
257         srv_conn->service->model_ops->terminate_connection(srv_conn, reason);
258 }
259
260 void server_io_handler(struct event_context *ev, struct fd_event *fde, time_t t, uint16_t flags)
261 {
262         struct server_connection *conn = fde->private;
263
264         conn->event.idle->next_event = t + conn->event.idle_time;
265
266         if (flags & EVENT_FD_WRITE) {
267                 conn->service->ops->send_handler(conn, t, flags);
268                 return;
269         }
270
271         if (flags & EVENT_FD_READ) {
272                 conn->service->ops->recv_handler(conn, t, flags);
273         }
274
275 }
276
277 void server_idle_handler(struct event_context *ev, struct timed_event *idle, time_t t)
278 {
279         struct server_connection *conn = idle->private;
280
281         conn->event.idle->next_event = t + conn->event.idle_time;
282
283         conn->service->ops->idle_handler(conn,t);
284 }
285 /*
286   return the operations structure for a named backend of the specified type
287 */
288 const struct server_service_ops *server_service_byname(const char *name)
289 {
290         if (strcmp("smb",name)==0) {
291                 return smbsrv_get_ops();
292         }
293         if (strcmp("rpc",name)==0) {
294                 return dcesrv_get_ops();
295         }
296         if (strcmp("ldap",name)==0) {
297                 return ldapsrv_get_ops();
298         }
299         return NULL;
300 }
301
302 static NTSTATUS register_server_service_ops(const void *_ops)
303 {
304         return NT_STATUS_NOT_IMPLEMENTED;
305 }
306
307 /*
308   initialise the SERVER SERVICE subsystem
309 */
310 BOOL server_service_init(void)
311 {
312         NTSTATUS status;
313
314         status = register_subsystem("service", register_server_service_ops); 
315         if (!NT_STATUS_IS_OK(status)) {
316                 return False;
317         }
318
319         /* FIXME: Perhaps panic if a basic endpoint server, such as EPMAPER, fails to initialise? */
320         static_init_server_service;
321
322         DEBUG(3,("SERVER SERVICE subsystem version %d initialised\n", SERVER_SERVICE_VERSION));
323         return True;
324 }