/* * Unix SMB/CIFS implementation. * * RPC Socket Helper * * Copyright (c) 2011 Andreas Schneider * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ #include "includes.h" #include "ntdomain.h" #include "../lib/tsocket/tsocket.h" #include "librpc/rpc/dcerpc_ep.h" #include "rpc_server/rpc_server.h" #include "rpc_server/rpc_sock_helper.h" NTSTATUS rpc_create_tcpip_sockets(const struct ndr_interface_table *iface, struct dcerpc_binding_vector *bvec, uint16_t port, int *listen_fd, int *listen_fd_size) { uint32_t num_ifs = iface_count(); uint32_t i; uint16_t p = port; TALLOC_CTX *tmp_ctx; NTSTATUS status = NT_STATUS_UNSUCCESSFUL; int rc; tmp_ctx = talloc_stackframe(); if (tmp_ctx == NULL) { return NT_STATUS_NO_MEMORY; } if (lp_interfaces() && lp_bind_interfaces_only()) { /* * We have been given an interfaces line, and been told to only * bind to those interfaces. Create a socket per interface and * bind to only these. */ /* Now open a listen socket for each of the interfaces. */ for (i = 0; i < num_ifs; i++) { const struct sockaddr_storage *ifss = iface_n_sockaddr_storage(i); struct tsocket_address *bind_addr; const char *addr; int fd; fd = create_tcpip_socket(ifss, &p); if (fd < 0 || p == 0) { status = NT_STATUS_UNSUCCESSFUL; goto done; } listen_fd[*listen_fd_size] = fd; (*listen_fd_size)++; if (bvec != NULL) { rc = tsocket_address_bsd_from_sockaddr(tmp_ctx, (struct sockaddr *)ifss, sizeof(struct sockaddr_storage), &bind_addr); if (rc < 0) { close(fd); status = NT_STATUS_NO_MEMORY; goto done; } addr = tsocket_address_inet_addr_string(bind_addr, tmp_ctx); if (addr == NULL) { close(fd); status = NT_STATUS_NO_MEMORY; goto done; } status = dcerpc_binding_vector_add_port(iface, bvec, addr, p); if (!NT_STATUS_IS_OK(status)) { close(fd); goto done; } } } } else { const char *sock_addr = lp_socket_address(); const char *sock_ptr; char *sock_tok; if (strequal(sock_addr, "0.0.0.0") || strequal(sock_addr, "::")) { #if HAVE_IPV6 sock_addr = "::,0.0.0.0"; #else sock_addr = "0.0.0.0"; #endif } for (sock_ptr = sock_addr; next_token_talloc(talloc_tos(), &sock_ptr, &sock_tok, " \t,"); ) { struct sockaddr_storage ss; int fd; /* open an incoming socket */ if (!interpret_string_addr(&ss, sock_tok, AI_NUMERICHOST|AI_PASSIVE)) { continue; } fd = create_tcpip_socket(&ss, &p); if (fd < 0 || p == 0) { status = NT_STATUS_UNSUCCESSFUL; goto done; } listen_fd[*listen_fd_size] = fd; (*listen_fd_size)++; if (bvec != NULL) { status = dcerpc_binding_vector_add_port(iface, bvec, sock_ptr, p); if (!NT_STATUS_IS_OK(status)) { close(fd); return status; } } } } status = NT_STATUS_OK; done: talloc_free(tmp_ctx); return status; } NTSTATUS rpc_setup_tcpip_sockets(struct tevent_context *ev_ctx, struct messaging_context *msg_ctx, const struct ndr_interface_table *iface, struct dcerpc_binding_vector *bvec, uint16_t port) { uint32_t num_ifs = iface_count(); uint32_t i; uint16_t p = 0; TALLOC_CTX *tmp_ctx; NTSTATUS status = NT_STATUS_UNSUCCESSFUL; int rc; tmp_ctx = talloc_stackframe(); if (tmp_ctx == NULL) { return NT_STATUS_NO_MEMORY; } if (lp_interfaces() && lp_bind_interfaces_only()) { /* * We have been given an interfaces line, and been told to only * bind to those interfaces. Create a socket per interface and * bind to only these. */ /* Now open a listen socket for each of the interfaces. */ for (i = 0; i < num_ifs; i++) { const struct sockaddr_storage *ifss = iface_n_sockaddr_storage(i); struct tsocket_address *bind_addr; const char *addr; p = setup_dcerpc_ncacn_tcpip_socket(ev_ctx, msg_ctx, ifss, port); if (p == 0) { status = NT_STATUS_UNSUCCESSFUL; goto done; } if (bvec != NULL) { rc = tsocket_address_bsd_from_sockaddr(tmp_ctx, (struct sockaddr*)ifss, sizeof(struct sockaddr_storage), &bind_addr); if (rc < 0) { return NT_STATUS_NO_MEMORY; } addr = tsocket_address_inet_addr_string(bind_addr, tmp_ctx); if (addr == NULL) { return NT_STATUS_NO_MEMORY; } status = dcerpc_binding_vector_add_port(iface, bvec, addr, p); if (!NT_STATUS_IS_OK(status)) { return status; } } } } else { const char *sock_addr = lp_socket_address(); const char *sock_ptr; char *sock_tok; if (strequal(sock_addr, "0.0.0.0") || strequal(sock_addr, "::")) { #if HAVE_IPV6 sock_addr = "::,0.0.0.0"; #else sock_addr = "0.0.0.0"; #endif } for (sock_ptr = sock_addr; next_token_talloc(talloc_tos(), &sock_ptr, &sock_tok, " \t,"); ) { struct sockaddr_storage ss; /* open an incoming socket */ if (!interpret_string_addr(&ss, sock_tok, AI_NUMERICHOST|AI_PASSIVE)) { continue; } p = setup_dcerpc_ncacn_tcpip_socket(ev_ctx, msg_ctx, &ss, port); if (p == 0) { return NT_STATUS_UNSUCCESSFUL; } if (bvec != NULL) { status = dcerpc_binding_vector_add_port(iface, bvec, sock_tok, p); if (!NT_STATUS_IS_OK(status)) { return status; } } } } status = NT_STATUS_OK; done: talloc_free(tmp_ctx); return status; } /* vim: set ts=8 sw=8 noet cindent syntax=c.doxygen: */