smbd: Simplify an if-condition
[Samba.git] / source3 / rpc_server / rpc_sock_helper.c
blob364b889d9b7855160f4200b54167f2dacd9c52ea
1 /*
2 * Unix SMB/CIFS implementation.
4 * RPC Socket Helper
6 * Copyright (c) 2011 Andreas Schneider <asn@samba.org>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, see <http://www.gnu.org/licenses/>.
22 #include "includes.h"
23 #include "ntdomain.h"
25 #include "../lib/tsocket/tsocket.h"
26 #include "librpc/rpc/dcesrv_core.h"
27 #include "rpc_server/rpc_sock_helper.h"
28 #include "librpc/ndr/ndr_table.h"
30 #undef DBGC_CLASS
31 #define DBGC_CLASS DBGC_RPC_SRV
33 static NTSTATUS dcesrv_create_ncacn_np_socket(
34 struct dcerpc_binding *b, int *out_fd)
36 char *np_dir = NULL;
37 int fd = -1;
38 NTSTATUS status;
39 const char *endpoint;
40 char *endpoint_normalized = NULL;
41 char *p = NULL;
43 endpoint = dcerpc_binding_get_string_option(b, "endpoint");
44 if (endpoint == NULL) {
45 DBG_ERR("Endpoint mandatory for named pipes\n");
46 return NT_STATUS_INVALID_PARAMETER;
49 /* The endpoint string from IDL can be mixed uppercase and case is
50 * normalized by smbd on connection */
51 endpoint_normalized = strlower_talloc(talloc_tos(), endpoint);
52 if (endpoint_normalized == NULL) {
53 return NT_STATUS_NO_MEMORY;
56 /* The endpoint string from IDL can be prefixed by \pipe\ */
57 p = endpoint_normalized;
58 if (strncmp(p, "\\pipe\\", 6) == 0) {
59 p += 6;
63 * As lp_ncalrpc_dir() should have 0755, but
64 * lp_ncalrpc_dir()/np should have 0700, we need to
65 * create lp_ncalrpc_dir() first.
67 if (!directory_create_or_exist(lp_ncalrpc_dir(), 0755)) {
68 status = map_nt_error_from_unix_common(errno);
69 DBG_ERR("Failed to create pipe directory %s - %s\n",
70 lp_ncalrpc_dir(), strerror(errno));
71 goto out;
74 np_dir = talloc_asprintf(talloc_tos(), "%s/np", lp_ncalrpc_dir());
75 if (!np_dir) {
76 status = NT_STATUS_NO_MEMORY;
77 DBG_ERR("Out of memory\n");
78 goto out;
81 if (!directory_create_or_exist_strict(np_dir, geteuid(), 0700)) {
82 status = map_nt_error_from_unix_common(errno);
83 DBG_ERR("Failed to create pipe directory %s - %s\n",
84 np_dir, strerror(errno));
85 goto out;
88 fd = create_pipe_sock(np_dir, p, 0700);
89 if (fd == -1) {
90 status = map_nt_error_from_unix_common(errno);
91 DBG_ERR("Failed to create ncacn_np socket! '%s/%s': %s\n",
92 np_dir, p, strerror(errno));
93 goto out;
96 DBG_DEBUG("Opened pipe socket fd %d for %s\n", fd, p);
98 *out_fd = fd;
100 status = NT_STATUS_OK;
102 out:
103 TALLOC_FREE(endpoint_normalized);
104 TALLOC_FREE(np_dir);
105 return status;
108 /********************************************************************
109 * Start listening on the tcp/ip socket
110 ********************************************************************/
112 static NTSTATUS dcesrv_create_ncacn_ip_tcp_socket(
113 const struct sockaddr_storage *ifss, uint16_t *port, int *out_fd)
115 int fd = -1;
117 if (*port == 0) {
118 static uint16_t low = 0;
119 uint16_t i;
121 if (low == 0) {
122 low = lp_rpc_low_port();
125 for (i = low; i <= lp_rpc_high_port(); i++) {
126 fd = open_socket_in(SOCK_STREAM, ifss, i, false);
127 if (fd >= 0) {
128 *port = i;
129 low = i+1;
130 break;
133 } else {
134 fd = open_socket_in(SOCK_STREAM, ifss, *port, true);
137 if (fd < 0) {
138 DBG_ERR("Failed to create socket on port %u!\n", *port);
139 return map_nt_error_from_unix(-fd);
142 /* ready to listen */
143 set_socket_options(fd, "SO_KEEPALIVE");
144 set_socket_options(fd, lp_socket_options());
146 DBG_DEBUG("Opened ncacn_ip_tcp socket fd %d for port %u\n", fd, *port);
148 *out_fd = fd;
150 return NT_STATUS_OK;
153 static NTSTATUS dcesrv_create_ncacn_ip_tcp_sockets(
154 struct dcerpc_binding *b,
155 TALLOC_CTX *mem_ctx,
156 size_t *pnum_fds,
157 int **pfds)
159 uint16_t port = 0;
160 char port_str[11];
161 const char *endpoint = NULL;
162 size_t i = 0, num_fds;
163 int *fds = NULL;
164 struct samba_sockaddr *addrs = NULL;
165 NTSTATUS status = NT_STATUS_INVALID_PARAMETER;
166 bool ok;
168 endpoint = dcerpc_binding_get_string_option(b, "endpoint");
169 if (endpoint != NULL) {
170 port = atoi(endpoint);
173 if (lp_interfaces() && lp_bind_interfaces_only()) {
174 num_fds = iface_count();
175 } else {
176 num_fds = 1;
177 #ifdef HAVE_IPV6
178 num_fds += 1;
179 #endif
182 addrs = talloc_array(mem_ctx, struct samba_sockaddr, num_fds);
183 if (addrs == NULL) {
184 status = NT_STATUS_NO_MEMORY;
185 goto fail;
187 fds = talloc_array(mem_ctx, int, num_fds);
188 if (fds == NULL) {
189 status = NT_STATUS_NO_MEMORY;
190 goto fail;
194 * Fill "addrs"
197 if (lp_interfaces() && lp_bind_interfaces_only()) {
198 for (i=0; i<num_fds; i++) {
199 const struct sockaddr_storage *ifss =
200 iface_n_sockaddr_storage(i);
202 ok = sockaddr_storage_to_samba_sockaddr(
203 &addrs[i], ifss);
204 if (!ok) {
205 i = 0; /* nothing to close */
206 goto fail;
209 } else {
210 struct sockaddr_storage ss = { .ss_family = 0 };
212 #ifdef HAVE_IPV6
213 ok = interpret_string_addr(
214 &ss, "::", AI_NUMERICHOST|AI_PASSIVE);
215 if (!ok) {
216 goto fail;
218 ok = sockaddr_storage_to_samba_sockaddr(&addrs[0], &ss);
219 if (!ok) {
220 goto fail;
222 #endif
223 ok = interpret_string_addr(
224 &ss, "0.0.0.0", AI_NUMERICHOST|AI_PASSIVE);
225 if (!ok) {
226 goto fail;
229 /* num_fds set above depending on HAVE_IPV6 */
230 ok = sockaddr_storage_to_samba_sockaddr(
231 &addrs[num_fds-1], &ss);
232 if (!ok) {
233 goto fail;
237 for (i=0; i<num_fds; i++) {
238 status = dcesrv_create_ncacn_ip_tcp_socket(
239 &addrs[i].u.ss, &port, &fds[i]);
240 if (!NT_STATUS_IS_OK(status)) {
241 goto fail;
243 samba_sockaddr_set_port(&addrs[i], port);
246 /* Set the port in the endpoint */
247 snprintf(port_str, sizeof(port_str), "%"PRIu16, port);
249 status = dcerpc_binding_set_string_option(b, "endpoint", port_str);
250 if (!NT_STATUS_IS_OK(status)) {
251 DBG_ERR("Failed to set binding endpoint '%s': %s\n",
252 port_str, nt_errstr(status));
253 goto fail;
256 TALLOC_FREE(addrs);
258 *pfds = fds;
259 *pnum_fds = num_fds;
261 return NT_STATUS_OK;
263 fail:
264 while (i > 0) {
265 close(fds[i-1]);
266 i -= 1;
268 TALLOC_FREE(fds);
269 TALLOC_FREE(addrs);
270 return status;
273 /********************************************************************
274 * Start listening on the ncalrpc socket
275 ********************************************************************/
277 static NTSTATUS dcesrv_create_ncalrpc_socket(
278 struct dcerpc_binding *b, int *out_fd)
280 int fd = -1;
281 const char *endpoint = NULL;
282 NTSTATUS status;
284 endpoint = dcerpc_binding_get_string_option(b, "endpoint");
285 if (endpoint == NULL) {
287 * No identifier specified: use DEFAULT or SMBD.
289 * When role is AD DC we run two rpc server instances, the one
290 * started by 'samba' and the one embedded in 'smbd'.
291 * Avoid listening in DEFAULT socket for NCALRPC as both
292 * servers will race to accept connections. In this case smbd
293 * will listen in SMBD socket and rpcint binding handle
294 * implementation will pick the right socket to use.
296 * TODO: DO NOT hardcode this value anywhere else. Rather,
297 * specify no endpoint and let the epmapper worry about it.
299 if (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC) {
300 endpoint = "SMBD";
301 } else {
302 endpoint = "DEFAULT";
304 status = dcerpc_binding_set_string_option(
305 b, "endpoint", endpoint);
306 if (!NT_STATUS_IS_OK(status)) {
307 DBG_ERR("Failed to set ncalrpc 'endpoint' binding "
308 "string option to '%s': %s\n",
309 endpoint, nt_errstr(status));
310 return status;
314 if (!directory_create_or_exist(lp_ncalrpc_dir(), 0755)) {
315 status = map_nt_error_from_unix_common(errno);
316 DBG_ERR("Failed to create ncalrpc directory '%s': %s\n",
317 lp_ncalrpc_dir(), strerror(errno));
318 goto out;
321 fd = create_pipe_sock(lp_ncalrpc_dir(), endpoint, 0755);
322 if (fd == -1) {
323 status = map_nt_error_from_unix_common(errno);
324 DBG_ERR("Failed to create ncalrpc socket '%s/%s': %s\n",
325 lp_ncalrpc_dir(), endpoint, strerror(errno));
326 goto out;
329 DBG_DEBUG("Opened ncalrpc socket fd '%d' for '%s/%s'\n",
330 fd, lp_ncalrpc_dir(), endpoint);
332 *out_fd = fd;
334 return NT_STATUS_OK;
336 out:
337 return status;
340 NTSTATUS dcesrv_create_binding_sockets(
341 struct dcerpc_binding *b,
342 TALLOC_CTX *mem_ctx,
343 size_t *pnum_fds,
344 int **pfds)
346 enum dcerpc_transport_t transport = dcerpc_binding_get_transport(b);
347 size_t i, num_fds = 1;
348 int *fds = NULL;
349 NTSTATUS status;
351 if ((transport == NCALRPC) || (transport == NCACN_NP)) {
352 fds = talloc(mem_ctx, int);
353 if (fds == NULL) {
354 return NT_STATUS_NO_MEMORY;
358 switch(transport) {
359 case NCALRPC:
360 status = dcesrv_create_ncalrpc_socket(b, fds);
361 break;
362 case NCACN_NP:
363 status = dcesrv_create_ncacn_np_socket(b, fds);
364 break;
365 case NCACN_IP_TCP:
366 status = dcesrv_create_ncacn_ip_tcp_sockets(
367 b, talloc_tos(), &num_fds, &fds);
368 break;
369 default:
370 status = NT_STATUS_NOT_SUPPORTED;
371 break;
374 if (!NT_STATUS_IS_OK(status)) {
375 TALLOC_FREE(fds);
376 return status;
379 for (i=0; i<num_fds; i++) {
380 bool ok = smb_set_close_on_exec(fds[i]);
381 if (!ok) {
382 status = map_nt_error_from_unix(errno);
383 break;
386 if (i < num_fds) {
387 for (i=0; i<num_fds; i++) {
388 close(fds[i]);
390 TALLOC_FREE(fds);
391 return status;
394 *pfds = fds;
395 *pnum_fds = num_fds;
396 return NT_STATUS_OK;
399 /* vim: set ts=8 sw=8 noet cindent syntax=c.doxygen: */