e0ec3cf07e2483bc3bd08a7685e0dc6d14c29b24
[samba.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 #include "events.h"
26 #include "system/dir.h"
27 #include "dlinklist.h"
28 #include "process_model.h"
29
30 struct server_context *server_service_startup(const char *model, const char **server_services)
31 {
32         int i;
33         struct server_context *server;
34
35         if (!server_services) {
36                 DEBUG(0,("server_service_startup: no endpoint servers configured\n"));
37                 return NULL;
38         }
39
40         server = talloc_zero(NULL, struct server_context);
41         if (!server) {
42                 return NULL;    
43         }
44
45         server->model.ops = process_model_startup(server, model);
46         if (!server->model.ops) {
47                 DEBUG(0,("process_model_startup('%s') failed\n", model));
48                 return NULL;
49         }
50
51         server->event.ctx = event_context_init(server);
52         if (!server->event.ctx) {
53                 DEBUG(0,("event_context_init() failed\n"));
54                 return NULL;
55         }
56
57         for (i=0;server_services[i];i++) {
58                 const struct server_service_ops *service_ops;
59                 struct server_service *service;
60
61                 service_ops = server_service_byname(server_services[i]);
62                 if (!service_ops) {
63                         DEBUG(0,("process_model_startup: failed to find server service = '%s'\n", server_services[i]));
64                         return NULL;
65                 }
66
67                 service = talloc_zero(server, struct server_service);
68                 if (!service) {
69                         return NULL;
70                 }
71
72                 service->service.ops    = service_ops;
73                 service->server         = server;
74
75                 /* TODO: service_init() should return a result */
76                 service->service.ops->service_init(service);
77
78                 DLIST_ADD(server->service_list, service);
79         }
80
81         return server;
82 }
83
84 void server_service_shutdown(struct server_context *server, const char *reason)
85 {
86         server->model.ops->model_exit(server, reason);
87 }
88
89 /*
90   setup a listen stream socket
91   if you pass *port == 0, then a port > 1024 is used
92  */
93 struct server_stream_socket *service_setup_stream_socket(struct server_service *service,
94                                                          const struct server_stream_ops *stream_ops,
95                                                          const char *family,
96                                                          const char *sock_addr,
97                                                          uint16_t *port)
98 {
99         NTSTATUS status;
100         struct server_stream_socket *stream_socket;
101         struct socket_context *sock;
102         struct fd_event fde;
103         int i;
104
105         status = socket_create(family, SOCKET_TYPE_STREAM, &sock, 0);
106         if (!NT_STATUS_IS_OK(status)) {
107                 DEBUG(0,("Failed to open socket on %s:%u - %s\n",
108                         sock_addr, *port, nt_errstr(status)));
109                 return NULL;
110         }
111
112         /* ready to listen */
113         status = socket_set_option(sock, "SO_KEEPALIVE SO_REUSEADDR=1", NULL);
114         if (!NT_STATUS_IS_OK(status)) {
115                 DEBUG(0,("socket_set_option(socket_ctx, SO_KEEPALIVE, NULL): %s\n",
116                         nt_errstr(status)));
117                 socket_destroy(sock);
118                 return NULL;
119         }
120         status = socket_set_option(sock, lp_socket_options(), NULL);
121         if (!NT_STATUS_IS_OK(status)) {
122                 DEBUG(0,("socket_set_option(socket_ctx, lp_socket_options(), NULL): %s\n",
123                         nt_errstr(status)));
124                 socket_destroy(sock);
125                 return NULL;
126         }
127
128         /* TODO: set socket ACL's here when they're implemented */
129
130         if (*port == 0) {
131                 for (i=SERVER_TCP_LOW_PORT;i<= SERVER_TCP_HIGH_PORT;i++) {
132                         status = socket_listen(sock, sock_addr, i, SERVER_LISTEN_BACKLOG, 0);
133                         if (NT_STATUS_IS_OK(status)) {
134                                 *port = i;
135                                 break;
136                         }
137                 }
138         } else {
139                 status = socket_listen(sock, sock_addr, *port, SERVER_LISTEN_BACKLOG, 0);
140         }
141
142         if (!NT_STATUS_IS_OK(status)) {
143                 DEBUG(0,("Failed to listen on %s:%u - %s\n",
144                         sock_addr, *port, nt_errstr(status)));
145                 socket_destroy(sock);
146                 return NULL;
147         }
148
149         stream_socket = talloc_zero(service, struct server_stream_socket);
150         if (!stream_socket) {
151                 DEBUG(0,("talloc_p(mem_ctx, struct server_stream_socket) failed\n"));
152                 socket_destroy(sock);
153                 return NULL;
154         }
155
156         /* we are only interested in read events on the listen socket */
157         fde.fd          = socket_get_fd(sock);
158         fde.flags       = EVENT_FD_READ;
159         fde.private     = stream_socket;
160         fde.handler     = server_accept_handler;
161
162         stream_socket->stream.ops       = stream_ops;
163         stream_socket->service          = service;
164         stream_socket->socket           = sock;
165         stream_socket->event.ctx        = service->server->event.ctx;
166         stream_socket->event.fde        = event_add_fd(stream_socket->event.ctx, &fde);
167         if (!stream_socket->event.fde) {
168                 DEBUG(0,("event_add_fd(stream_socket->event.ctx, &fde) failed\n"));
169                 socket_destroy(sock);
170                 return NULL;
171         }
172
173         talloc_steal(stream_socket, sock);
174
175         if (stream_socket->stream.ops->socket_init) {
176                 stream_socket->stream.ops->socket_init(stream_socket);
177         }
178
179         return stream_socket;
180 }
181
182 /*
183   destructor that handles necessary event context changes
184  */
185 static int server_connection_destructor(void *ptr)
186 {
187         struct server_connection *conn = ptr;
188
189         if (conn->stream_socket && 
190             conn->stream_socket->stream.ops->close_connection) {
191                 /* don't remove this! the stream service needs to free it's data
192                  * before we destroy the server_connection
193                  */
194                 conn->stream_socket->stream.ops->close_connection(conn, "shutdown");
195         }
196
197         if (conn->event.fde) {
198                 event_remove_fd(conn->event.ctx, conn->event.fde);
199                 conn->event.fde = NULL;
200         }
201         if (conn->event.idle) {
202                 event_remove_timed(conn->event.ctx, conn->event.idle);
203                 conn->event.idle = NULL;
204         }
205
206         return 0;
207 }
208
209 struct server_connection *server_setup_connection(struct event_context *ev, 
210                                                   struct server_stream_socket *stream_socket, 
211                                                   struct socket_context *sock, 
212                                                   struct timeval t,
213                                                   servid_t server_id)
214 {
215         struct fd_event fde;
216         struct timed_event idle;
217         struct server_connection *srv_conn;
218
219         srv_conn = talloc_p(stream_socket, struct server_connection);
220         if (!srv_conn) {
221                 DEBUG(0,("talloc_p(mem_ctx, struct server_connection) failed\n"));
222                 return NULL;
223         }
224
225         ZERO_STRUCTP(srv_conn);
226
227         fde.private     = srv_conn;
228         fde.fd          = socket_get_fd(sock);
229         fde.flags       = EVENT_FD_READ;
230         fde.handler     = server_io_handler;
231
232         idle.private    = srv_conn;
233         idle.next_event = timeval_add(&t, SERVER_DEFAULT_IDLE_TIME, 0);
234         idle.handler    = server_idle_handler;
235
236         srv_conn->event.ctx             = ev;
237         srv_conn->event.fde             = &fde;
238         srv_conn->event.idle            = &idle;
239         srv_conn->event.idle_time       = timeval_set(SERVER_DEFAULT_IDLE_TIME, 0);
240
241         srv_conn->stream_socket         = stream_socket;
242         srv_conn->socket                = sock;
243         srv_conn->connection.id         = server_id;
244
245         /* create a server context and add it to out event
246            handling */
247         stream_socket->stream.ops->accept_connection(srv_conn);
248
249         /* accpect_connection() of the service may changed idle.next_event */
250         srv_conn->event.fde     = event_add_fd(ev,&fde);
251         srv_conn->event.idle    = event_add_timed(ev,&idle);
252
253         talloc_set_destructor(srv_conn, server_connection_destructor);
254
255         if (!socket_check_access(sock, "smbd", lp_hostsallow(-1), lp_hostsdeny(-1))) {
256                 server_terminate_connection(srv_conn, "denied by access rules");
257                 return NULL;
258         }
259
260         /* setup to receive internal messages on this connection */
261         srv_conn->messaging.ctx = messaging_init(srv_conn, srv_conn->connection.id, ev);
262         if (!srv_conn->messaging.ctx) {
263                 server_terminate_connection(srv_conn, "messaging_init() failed");
264                 return NULL;
265         }
266
267         return srv_conn;
268 }
269
270 /*
271   close the socket and shutdown a server_context
272 */
273 void server_terminate_connection(struct server_connection *srv_conn, const char *reason)
274 {
275         DEBUG(2,("server_terminate_connection\n"));
276         srv_conn->stream_socket->service->server->model.ops->terminate_connection(srv_conn, reason);
277 }
278
279 void server_accept_handler(struct event_context *ev, struct fd_event *fde, 
280                        struct timeval t, uint16_t flags)
281 {
282         struct server_stream_socket *stream_socket = fde->private;
283
284         stream_socket->service->server->model.ops->accept_connection(ev, fde, t, flags);
285 }
286
287 void server_io_handler(struct event_context *ev, struct fd_event *fde, 
288                        struct timeval t, uint16_t flags)
289 {
290         struct server_connection *conn = fde->private;
291
292         conn->event.idle->next_event = timeval_sum(&t,  &conn->event.idle_time);
293
294         if (flags & EVENT_FD_WRITE) {
295                 conn->stream_socket->stream.ops->send_handler(conn, t, flags);
296                 return;
297         }
298
299         if (flags & EVENT_FD_READ) {
300                 conn->stream_socket->stream.ops->recv_handler(conn, t, flags);
301         }
302
303 }
304
305 void server_idle_handler(struct event_context *ev, struct timed_event *idle, 
306                          struct timeval t)
307 {
308         struct server_connection *conn = idle->private;
309
310         /* Not all services provide an idle handler */
311         if (conn->stream_socket->stream.ops->idle_handler) {
312                 conn->event.idle->next_event = timeval_sum(&t, &conn->event.idle_time);
313                 conn->stream_socket->stream.ops->idle_handler(conn, t);
314         }
315 }
316
317 void server_terminate_task(struct server_task *task, const char *reason)
318 {
319         task->service->server->model.ops->terminate_task(task, reason);
320         return;
321 }
322
323 void server_run_task(struct server_service *service, const struct server_task_ops *ops)
324 {
325         struct server_task *task;
326
327         task = talloc_zero(service, struct server_task);
328         if (!task) {
329                 return;
330         }
331         task->service           = service;
332         task->task.ops          = ops;
333
334         service->server->model.ops->create_task(task);
335         return;
336 }
337
338 /*
339   return the operations structure for a named backend of the specified type
340 */
341 const struct server_service_ops *server_service_byname(const char *name)
342 {
343         if (strcmp("smb",name)==0) {
344                 return smbsrv_get_ops();
345         }
346         if (strcmp("rpc",name)==0) {
347                 return dcesrv_get_ops();
348         }
349         if (strcmp("ldap",name)==0) {
350                 return ldapsrv_get_ops();
351         }
352         return NULL;
353 }
354
355 NTSTATUS register_server_service_ops(const void *_ops)
356 {
357         return NT_STATUS_NOT_IMPLEMENTED;
358 }
359
360 /*
361   cleanup temporary files. This is the new alternative to
362   TDB_CLEAR_IF_FIRST. Unfortunately TDB_CLEAR_IF_FIRST is not
363   efficient on unix systems due to the lack of scaling of the byte
364   range locking system. So instead of putting the burden on tdb to
365   cleanup tmp files, this function deletes them. 
366 */
367 void service_cleanup_tmp_files(void)
368 {
369         char *path;
370         DIR *dir;
371         struct dirent *de;
372         TALLOC_CTX *mem_ctx = talloc_init("service_cleanup_tmp_files");
373
374         path = smbd_tmp_path(mem_ctx, NULL);
375
376         dir = opendir(path);
377         if (!dir) {
378                 talloc_free(mem_ctx);
379                 return;
380         }
381
382         for (de=readdir(dir);de;de=readdir(dir)) {
383                 char *fname = talloc_asprintf(mem_ctx, "%s/%s", path, de->d_name);
384                 int ret = unlink(fname);
385                 if (ret == -1 &&
386                     errno != ENOENT &&
387                     errno != EISDIR &&
388                     errno != EISDIR) {
389                         DEBUG(0,("Unabled to delete '%s' - %s\n", 
390                                  fname, strerror(errno)));
391                         smb_panic("unable to cleanup tmp files");
392                 }
393                 talloc_free(fname);
394         }
395         closedir(dir);
396
397         talloc_free(mem_ctx);
398 }