messaging4: Add NULL check to irpc_add_name
[Samba.git] / source4 / smbd / service_stream.c
blob11e6deb35de2da264d6e134141e66918b7aef4e7
1 /*
2 Unix SMB/CIFS implementation.
4 helper functions for stream based servers
6 Copyright (C) Andrew Tridgell 2003-2005
7 Copyright (C) Stefan (metze) Metzmacher 2004
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 3 of the License, or
12 (at your option) any later version.
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.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "includes.h"
24 #include <tevent.h>
25 #include "process_model.h"
26 #include "lib/messaging/irpc.h"
27 #include "cluster/cluster.h"
28 #include "param/param.h"
29 #include "../lib/tsocket/tsocket.h"
30 #include "lib/util/util_net.h"
32 /* the range of ports to try for dcerpc over tcp endpoints */
33 #define SERVER_TCP_LOW_PORT 1024
34 #define SERVER_TCP_HIGH_PORT 1300
36 /* size of listen() backlog in smbd */
37 #define SERVER_LISTEN_BACKLOG 10
41 private structure for a single listening stream socket
43 struct stream_socket {
44 const struct stream_server_ops *ops;
45 struct loadparm_context *lp_ctx;
46 struct tevent_context *event_ctx;
47 const struct model_ops *model_ops;
48 struct socket_context *sock;
49 void *private_data;
54 close the socket and shutdown a stream_connection
56 void stream_terminate_connection(struct stream_connection *srv_conn, const char *reason)
58 struct tevent_context *event_ctx = srv_conn->event.ctx;
59 const struct model_ops *model_ops = srv_conn->model_ops;
61 if (!reason) reason = "unknown reason";
63 if (srv_conn->processing) {
64 DEBUG(3,("Terminating connection deferred - '%s'\n", reason));
65 } else {
66 DEBUG(3,("Terminating connection - '%s'\n", reason));
69 srv_conn->terminate = reason;
71 if (srv_conn->processing) {
72 /*
73 * if we're currently inside the stream_io_handler(),
74 * defer the termination to the end of stream_io_hendler()
76 * and we don't want to read or write to the connection...
78 tevent_fd_set_flags(srv_conn->event.fde, 0);
79 return;
82 talloc_free(srv_conn->event.fde);
83 srv_conn->event.fde = NULL;
84 imessaging_cleanup(srv_conn->msg_ctx);
85 model_ops->terminate(event_ctx, srv_conn->lp_ctx, reason);
86 talloc_free(srv_conn);
89 /**
90 the select loop has indicated that a stream is ready for IO
92 static void stream_io_handler(struct stream_connection *conn, uint16_t flags)
94 conn->processing++;
95 if (flags & TEVENT_FD_WRITE) {
96 conn->ops->send_handler(conn, flags);
97 } else if (flags & TEVENT_FD_READ) {
98 conn->ops->recv_handler(conn, flags);
100 conn->processing--;
102 if (conn->terminate) {
103 stream_terminate_connection(conn, conn->terminate);
107 void stream_io_handler_fde(struct tevent_context *ev, struct tevent_fd *fde,
108 uint16_t flags, void *private_data)
110 struct stream_connection *conn = talloc_get_type(private_data,
111 struct stream_connection);
112 stream_io_handler(conn, flags);
115 void stream_io_handler_callback(void *private_data, uint16_t flags)
117 struct stream_connection *conn = talloc_get_type(private_data,
118 struct stream_connection);
119 stream_io_handler(conn, flags);
123 this creates a stream_connection from an already existing connection,
124 used for protocols, where a client connection needs to switched into
125 a server connection
127 NTSTATUS stream_new_connection_merge(struct tevent_context *ev,
128 struct loadparm_context *lp_ctx,
129 const struct model_ops *model_ops,
130 const struct stream_server_ops *stream_ops,
131 struct imessaging_context *msg_ctx,
132 void *private_data,
133 struct stream_connection **_srv_conn)
135 struct stream_connection *srv_conn;
137 srv_conn = talloc_zero(ev, struct stream_connection);
138 NT_STATUS_HAVE_NO_MEMORY(srv_conn);
140 srv_conn->private_data = private_data;
141 srv_conn->model_ops = model_ops;
142 srv_conn->socket = NULL;
143 srv_conn->server_id = cluster_id(0, 0);
144 srv_conn->ops = stream_ops;
145 srv_conn->msg_ctx = msg_ctx;
146 srv_conn->event.ctx = ev;
147 srv_conn->lp_ctx = lp_ctx;
148 srv_conn->event.fde = NULL;
150 *_srv_conn = srv_conn;
151 return NT_STATUS_OK;
155 called when a new socket connection has been established. This is called in the process
156 context of the new process (if appropriate)
158 static void stream_new_connection(struct tevent_context *ev,
159 struct loadparm_context *lp_ctx,
160 struct socket_context *sock,
161 struct server_id server_id, void *private_data)
163 struct stream_socket *stream_socket = talloc_get_type(private_data, struct stream_socket);
164 struct stream_connection *srv_conn;
166 srv_conn = talloc_zero(ev, struct stream_connection);
167 if (!srv_conn) {
168 DEBUG(0,("talloc(mem_ctx, struct stream_connection) failed\n"));
169 return;
172 talloc_steal(srv_conn, sock);
174 srv_conn->private_data = stream_socket->private_data;
175 srv_conn->model_ops = stream_socket->model_ops;
176 srv_conn->socket = sock;
177 srv_conn->server_id = server_id;
178 srv_conn->ops = stream_socket->ops;
179 srv_conn->event.ctx = ev;
180 srv_conn->lp_ctx = lp_ctx;
182 if (!socket_check_access(sock, "smbd", lpcfg_hosts_allow(NULL, lpcfg_default_service(lp_ctx)), lpcfg_hosts_deny(NULL, lpcfg_default_service(lp_ctx)))) {
183 stream_terminate_connection(srv_conn, "denied by access rules");
184 return;
187 srv_conn->event.fde = tevent_add_fd(ev, srv_conn, socket_get_fd(sock),
188 0, stream_io_handler_fde, srv_conn);
189 if (!srv_conn->event.fde) {
190 stream_terminate_connection(srv_conn, "tevent_add_fd() failed");
191 return;
194 /* setup to receive internal messages on this connection */
195 srv_conn->msg_ctx = imessaging_init(srv_conn,
196 lp_ctx,
197 srv_conn->server_id, ev, false);
198 if (!srv_conn->msg_ctx) {
199 stream_terminate_connection(srv_conn, "imessaging_init() failed");
200 return;
203 srv_conn->remote_address = socket_get_remote_addr(srv_conn->socket, srv_conn);
204 if (!srv_conn->remote_address) {
205 stream_terminate_connection(srv_conn, "socket_get_remote_addr() failed");
206 return;
209 srv_conn->local_address = socket_get_local_addr(srv_conn->socket, srv_conn);
210 if (!srv_conn->local_address) {
211 stream_terminate_connection(srv_conn, "socket_get_local_addr() failed");
212 return;
216 TALLOC_CTX *tmp_ctx;
217 const char *title;
219 tmp_ctx = talloc_new(srv_conn);
221 title = talloc_asprintf(tmp_ctx, "conn[%s] c[%s] s[%s] server_id[%s]",
222 stream_socket->ops->name,
223 tsocket_address_string(srv_conn->remote_address, tmp_ctx),
224 tsocket_address_string(srv_conn->local_address, tmp_ctx),
225 server_id_str(tmp_ctx, &server_id));
226 if (title) {
227 stream_connection_set_title(srv_conn, title);
229 talloc_free(tmp_ctx);
232 /* we're now ready to start receiving events on this stream */
233 TEVENT_FD_READABLE(srv_conn->event.fde);
235 /* call the server specific accept code */
236 stream_socket->ops->accept_connection(srv_conn);
241 called when someone opens a connection to one of our listening ports
243 static void stream_accept_handler(struct tevent_context *ev, struct tevent_fd *fde,
244 uint16_t flags, void *private_data)
246 struct stream_socket *stream_socket = talloc_get_type(private_data, struct stream_socket);
248 /* ask the process model to create us a process for this new
249 connection. When done, it calls stream_new_connection()
250 with the newly created socket */
251 stream_socket->model_ops->accept_connection(ev, stream_socket->lp_ctx,
252 stream_socket->sock,
253 stream_new_connection, stream_socket);
257 setup a listen stream socket
258 if you pass *port == 0, then a port > 1024 is used
260 FIXME: This function is TCP/IP specific - uses an int rather than
261 a string for the port. Should leave allocating a port nr
262 to the socket implementation - JRV20070903
264 NTSTATUS stream_setup_socket(TALLOC_CTX *mem_ctx,
265 struct tevent_context *event_context,
266 struct loadparm_context *lp_ctx,
267 const struct model_ops *model_ops,
268 const struct stream_server_ops *stream_ops,
269 const char *family,
270 const char *sock_addr,
271 uint16_t *port,
272 const char *socket_options,
273 void *private_data)
275 NTSTATUS status;
276 struct stream_socket *stream_socket;
277 struct socket_address *socket_address;
278 struct tevent_fd *fde;
279 int i;
280 struct sockaddr_storage ss;
282 stream_socket = talloc_zero(mem_ctx, struct stream_socket);
283 NT_STATUS_HAVE_NO_MEMORY(stream_socket);
285 if (strcmp(family, "ip") == 0) {
286 /* we will get the real family from the address itself */
287 if (!interpret_string_addr(&ss, sock_addr, 0)) {
288 talloc_free(stream_socket);
289 return NT_STATUS_INVALID_ADDRESS;
292 socket_address = socket_address_from_sockaddr_storage(stream_socket, &ss, port?*port:0);
293 if (socket_address == NULL) {
294 TALLOC_FREE(stream_socket);
295 return NT_STATUS_NO_MEMORY;
298 status = socket_create(socket_address->family, SOCKET_TYPE_STREAM, &stream_socket->sock, 0);
299 NT_STATUS_NOT_OK_RETURN(status);
300 } else {
301 status = socket_create(family, SOCKET_TYPE_STREAM, &stream_socket->sock, 0);
302 NT_STATUS_NOT_OK_RETURN(status);
304 /* this is for non-IP sockets, eg. unix domain sockets */
305 socket_address = socket_address_from_strings(stream_socket,
306 stream_socket->sock->backend_name,
307 sock_addr, port?*port:0);
308 NT_STATUS_HAVE_NO_MEMORY(socket_address);
312 talloc_steal(stream_socket, stream_socket->sock);
314 stream_socket->lp_ctx = talloc_reference(stream_socket, lp_ctx);
316 /* ready to listen */
317 status = socket_set_option(stream_socket->sock, "SO_KEEPALIVE", NULL);
318 NT_STATUS_NOT_OK_RETURN(status);
320 if (socket_options != NULL) {
321 status = socket_set_option(stream_socket->sock, socket_options, NULL);
322 NT_STATUS_NOT_OK_RETURN(status);
325 /* TODO: set socket ACL's (host allow etc) here when they're
326 * implemented */
328 /* Some sockets don't have a port, or are just described from
329 * the string. We are indicating this by having port == NULL */
330 if (!port) {
331 status = socket_listen(stream_socket->sock, socket_address, SERVER_LISTEN_BACKLOG, 0);
332 } else if (*port == 0) {
333 for (i=SERVER_TCP_LOW_PORT;i<= SERVER_TCP_HIGH_PORT;i++) {
334 socket_address->port = i;
335 status = socket_listen(stream_socket->sock, socket_address,
336 SERVER_LISTEN_BACKLOG, 0);
337 if (NT_STATUS_IS_OK(status)) {
338 *port = i;
339 break;
342 } else {
343 status = socket_listen(stream_socket->sock, socket_address, SERVER_LISTEN_BACKLOG, 0);
346 if (!NT_STATUS_IS_OK(status)) {
347 DEBUG(0,("Failed to listen on %s:%u - %s\n",
348 sock_addr, port ? (unsigned int)(*port) : 0,
349 nt_errstr(status)));
350 talloc_free(stream_socket);
351 return status;
354 /* Add the FD from the newly created socket into the event
355 * subsystem. it will call the accept handler whenever we get
356 * new connections */
358 fde = tevent_add_fd(event_context, stream_socket->sock,
359 socket_get_fd(stream_socket->sock),
360 TEVENT_FD_READ,
361 stream_accept_handler, stream_socket);
362 if (!fde) {
363 DEBUG(0,("Failed to setup fd event\n"));
364 talloc_free(stream_socket);
365 return NT_STATUS_NO_MEMORY;
368 /* we let events system to the close on the socket. This avoids
369 * nasty interactions with waiting for talloc to close the socket. */
370 tevent_fd_set_close_fn(fde, socket_tevent_fd_close_fn);
371 socket_set_flags(stream_socket->sock, SOCKET_FLAG_NOCLOSE);
373 stream_socket->private_data = talloc_reference(stream_socket, private_data);
374 stream_socket->ops = stream_ops;
375 stream_socket->event_ctx = event_context;
376 stream_socket->model_ops = model_ops;
378 return NT_STATUS_OK;
383 setup a connection title
385 void stream_connection_set_title(struct stream_connection *conn, const char *title)
387 conn->model_ops->set_title(conn->event.ctx, title);