LCOV - code coverage report
Current view: top level - source3/rpc_server - rpc_sock_helper.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 118 198 59.6 %
Date: 2024-04-21 15:09:00 Functions: 5 5 100.0 %

          Line data    Source code
       1             : /*
       2             :  *  Unix SMB/CIFS implementation.
       3             :  *
       4             :  *  RPC Socket Helper
       5             :  *
       6             :  *  Copyright (c) 2011      Andreas Schneider <asn@samba.org>
       7             :  *
       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.
      12             :  *
      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.
      17             :  *
      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/>.
      20             :  */
      21             : 
      22             : #include "includes.h"
      23             : #include "ntdomain.h"
      24             : 
      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"
      29             : 
      30             : #undef DBGC_CLASS
      31             : #define DBGC_CLASS DBGC_RPC_SRV
      32             : 
      33        1523 : static NTSTATUS dcesrv_create_ncacn_np_socket(
      34             :         struct dcerpc_binding *b, int *out_fd)
      35             : {
      36        1523 :         char *np_dir = NULL;
      37        1523 :         int fd = -1;
      38           0 :         NTSTATUS status;
      39           0 :         const char *endpoint;
      40        1523 :         char *endpoint_normalized = NULL;
      41        1523 :         char *p = NULL;
      42             : 
      43        1523 :         endpoint = dcerpc_binding_get_string_option(b, "endpoint");
      44        1523 :         if (endpoint == NULL) {
      45           0 :                 DBG_ERR("Endpoint mandatory for named pipes\n");
      46           0 :                 return NT_STATUS_INVALID_PARAMETER;
      47             :         }
      48             : 
      49             :         /* The endpoint string from IDL can be mixed uppercase and case is
      50             :          * normalized by smbd on connection */
      51        1523 :         endpoint_normalized = strlower_talloc(talloc_tos(), endpoint);
      52        1523 :         if (endpoint_normalized == NULL) {
      53           0 :                 return NT_STATUS_NO_MEMORY;
      54             :         }
      55             : 
      56             :         /* The endpoint string from IDL can be prefixed by \pipe\ */
      57        1523 :         p = endpoint_normalized;
      58        1523 :         if (strncmp(p, "\\pipe\\", 6) == 0) {
      59        1523 :                 p += 6;
      60             :         }
      61             : 
      62             :         /*
      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.
      66             :          */
      67        1523 :         if (!directory_create_or_exist(lp_ncalrpc_dir(), 0755)) {
      68           0 :                 status = map_nt_error_from_unix_common(errno);
      69           0 :                 DBG_ERR("Failed to create pipe directory %s - %s\n",
      70             :                         lp_ncalrpc_dir(), strerror(errno));
      71           0 :                 goto out;
      72             :         }
      73             : 
      74        1523 :         np_dir = talloc_asprintf(talloc_tos(), "%s/np", lp_ncalrpc_dir());
      75        1523 :         if (!np_dir) {
      76           0 :                 status = NT_STATUS_NO_MEMORY;
      77           0 :                 DBG_ERR("Out of memory\n");
      78           0 :                 goto out;
      79             :         }
      80             : 
      81        1523 :         if (!directory_create_or_exist_strict(np_dir, geteuid(), 0700)) {
      82           0 :                 status = map_nt_error_from_unix_common(errno);
      83           0 :                 DBG_ERR("Failed to create pipe directory %s - %s\n",
      84             :                         np_dir, strerror(errno));
      85           0 :                 goto out;
      86             :         }
      87             : 
      88        1523 :         fd = create_pipe_sock(np_dir, p, 0700);
      89        1523 :         if (fd == -1) {
      90           0 :                 status = map_nt_error_from_unix_common(errno);
      91           0 :                 DBG_ERR("Failed to create ncacn_np socket! '%s/%s': %s\n",
      92             :                         np_dir, p, strerror(errno));
      93           0 :                 goto out;
      94             :         }
      95             : 
      96        1523 :         DBG_DEBUG("Opened pipe socket fd %d for %s\n", fd, p);
      97             : 
      98        1523 :         *out_fd = fd;
      99             : 
     100        1523 :         status = NT_STATUS_OK;
     101             : 
     102        1523 : out:
     103        1523 :         TALLOC_FREE(endpoint_normalized);
     104        1523 :         TALLOC_FREE(np_dir);
     105        1523 :         return status;
     106             : }
     107             : 
     108             : /********************************************************************
     109             :  * Start listening on the tcp/ip socket
     110             :  ********************************************************************/
     111             : 
     112         160 : static NTSTATUS dcesrv_create_ncacn_ip_tcp_socket(
     113             :         const struct sockaddr_storage *ifss, uint16_t *port, int *out_fd)
     114             : {
     115         160 :         int fd = -1;
     116             : 
     117         160 :         if (*port == 0) {
     118           0 :                 static uint16_t low = 0;
     119           0 :                 uint16_t i;
     120             : 
     121          64 :                 if (low == 0) {
     122          16 :                         low = lp_rpc_low_port();
     123             :                 }
     124             : 
     125          64 :                 for (i = low; i <= lp_rpc_high_port(); i++) {
     126          64 :                         fd = open_socket_in(SOCK_STREAM, ifss, i, false);
     127          64 :                         if (fd >= 0) {
     128          64 :                                 *port = i;
     129          64 :                                 low = i+1;
     130          64 :                                 break;
     131             :                         }
     132             :                 }
     133             :         } else {
     134          96 :                 fd = open_socket_in(SOCK_STREAM, ifss, *port, true);
     135             :         }
     136             : 
     137         160 :         if (fd < 0) {
     138           0 :                 DBG_ERR("Failed to create socket on port %u!\n", *port);
     139           0 :                 return map_nt_error_from_unix(-fd);
     140             :         }
     141             : 
     142             :         /* ready to listen */
     143         160 :         set_socket_options(fd, "SO_KEEPALIVE");
     144         160 :         set_socket_options(fd, lp_socket_options());
     145             : 
     146         160 :         DBG_DEBUG("Opened ncacn_ip_tcp socket fd %d for port %u\n", fd, *port);
     147             : 
     148         160 :         *out_fd = fd;
     149             : 
     150         160 :         return NT_STATUS_OK;
     151             : }
     152             : 
     153          80 : 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)
     158             : {
     159          80 :         uint16_t port = 0;
     160           0 :         char port_str[11];
     161          80 :         const char *endpoint = NULL;
     162          80 :         size_t i = 0, num_fds;
     163          80 :         int *fds = NULL;
     164          80 :         struct samba_sockaddr *addrs = NULL;
     165          80 :         NTSTATUS status = NT_STATUS_INVALID_PARAMETER;
     166           0 :         bool ok;
     167             : 
     168          80 :         endpoint = dcerpc_binding_get_string_option(b, "endpoint");
     169          80 :         if (endpoint != NULL) {
     170          16 :                 port = atoi(endpoint);
     171             :         }
     172             : 
     173          80 :         if (lp_interfaces() && lp_bind_interfaces_only()) {
     174          80 :                 num_fds = iface_count();
     175             :         } else {
     176           0 :                 num_fds = 1;
     177             : #ifdef HAVE_IPV6
     178           0 :                 num_fds += 1;
     179             : #endif
     180             :         }
     181             : 
     182          80 :         addrs = talloc_array(mem_ctx, struct samba_sockaddr, num_fds);
     183          80 :         if (addrs == NULL) {
     184           0 :                 status = NT_STATUS_NO_MEMORY;
     185           0 :                 goto fail;
     186             :         }
     187          80 :         fds = talloc_array(mem_ctx, int, num_fds);
     188          80 :         if (fds == NULL) {
     189           0 :                 status = NT_STATUS_NO_MEMORY;
     190           0 :                 goto fail;
     191             :         }
     192             : 
     193             :         /*
     194             :          * Fill "addrs"
     195             :          */
     196             : 
     197         105 :         if (lp_interfaces() && lp_bind_interfaces_only()) {
     198         240 :                 for (i=0; i<num_fds; i++) {
     199           0 :                         const struct sockaddr_storage *ifss =
     200         160 :                                 iface_n_sockaddr_storage(i);
     201             : 
     202         160 :                         ok = sockaddr_storage_to_samba_sockaddr(
     203         160 :                                 &addrs[i], ifss);
     204         160 :                         if (!ok) {
     205           0 :                                 i = 0; /* nothing to close */
     206           0 :                                 goto fail;
     207             :                         }
     208             :                 }
     209             :         } else {
     210           0 :                 struct sockaddr_storage ss = { .ss_family = 0 };
     211             : 
     212             : #ifdef HAVE_IPV6
     213           0 :                 ok = interpret_string_addr(
     214             :                         &ss, "::", AI_NUMERICHOST|AI_PASSIVE);
     215           0 :                 if (!ok) {
     216           0 :                         goto fail;
     217             :                 }
     218           0 :                 ok = sockaddr_storage_to_samba_sockaddr(&addrs[0], &ss);
     219           0 :                 if (!ok) {
     220           0 :                         goto fail;
     221             :                 }
     222             : #endif
     223           0 :                 ok = interpret_string_addr(
     224             :                         &ss, "0.0.0.0", AI_NUMERICHOST|AI_PASSIVE);
     225           0 :                 if (!ok) {
     226           0 :                         goto fail;
     227             :                 }
     228             : 
     229             :                 /* num_fds set above depending on HAVE_IPV6 */
     230           0 :                 ok = sockaddr_storage_to_samba_sockaddr(
     231           0 :                         &addrs[num_fds-1], &ss);
     232           0 :                 if (!ok) {
     233           0 :                         goto fail;
     234             :                 }
     235             :         }
     236             : 
     237         240 :         for (i=0; i<num_fds; i++) {
     238         160 :                 status = dcesrv_create_ncacn_ip_tcp_socket(
     239         160 :                         &addrs[i].u.ss, &port, &fds[i]);
     240         160 :                 if (!NT_STATUS_IS_OK(status)) {
     241           0 :                         goto fail;
     242             :                 }
     243         160 :                 samba_sockaddr_set_port(&addrs[i], port);
     244             :         }
     245             : 
     246             :         /* Set the port in the endpoint */
     247          80 :         snprintf(port_str, sizeof(port_str), "%"PRIu16, port);
     248             : 
     249          80 :         status = dcerpc_binding_set_string_option(b, "endpoint", port_str);
     250          80 :         if (!NT_STATUS_IS_OK(status)) {
     251           0 :                 DBG_ERR("Failed to set binding endpoint '%s': %s\n",
     252             :                         port_str, nt_errstr(status));
     253           0 :                 goto fail;
     254             :         }
     255             : 
     256          80 :         TALLOC_FREE(addrs);
     257             : 
     258          80 :         *pfds = fds;
     259          80 :         *pnum_fds = num_fds;
     260             : 
     261          80 :         return NT_STATUS_OK;
     262             : 
     263           0 : fail:
     264           0 :         while (i > 0) {
     265           0 :                 close(fds[i-1]);
     266           0 :                 i -= 1;
     267             :         }
     268           0 :         TALLOC_FREE(fds);
     269           0 :         TALLOC_FREE(addrs);
     270           0 :         return status;
     271             : }
     272             : 
     273             : /********************************************************************
     274             :  * Start listening on the ncalrpc socket
     275             :  ********************************************************************/
     276             : 
     277         112 : static NTSTATUS dcesrv_create_ncalrpc_socket(
     278             :         struct dcerpc_binding *b, int *out_fd)
     279             : {
     280         112 :         int fd = -1;
     281         112 :         const char *endpoint = NULL;
     282           0 :         NTSTATUS status;
     283             : 
     284         112 :         endpoint = dcerpc_binding_get_string_option(b, "endpoint");
     285         112 :         if (endpoint == NULL) {
     286             :                 /*
     287             :                  * No identifier specified: use DEFAULT or SMBD.
     288             :                  *
     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.
     295             :                  *
     296             :                  * TODO: DO NOT hardcode this value anywhere else. Rather,
     297             :                  * specify no endpoint and let the epmapper worry about it.
     298             :                  */
     299           0 :                 if (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC) {
     300           0 :                         endpoint = "SMBD";
     301             :                 } else {
     302           0 :                         endpoint = "DEFAULT";
     303             :                 }
     304           0 :                 status = dcerpc_binding_set_string_option(
     305             :                         b, "endpoint", endpoint);
     306           0 :                 if (!NT_STATUS_IS_OK(status)) {
     307           0 :                         DBG_ERR("Failed to set ncalrpc 'endpoint' binding "
     308             :                                 "string option to '%s': %s\n",
     309             :                                 endpoint, nt_errstr(status));
     310           0 :                         return status;
     311             :                 }
     312             :         }
     313             : 
     314         112 :         if (!directory_create_or_exist(lp_ncalrpc_dir(), 0755)) {
     315           0 :                 status = map_nt_error_from_unix_common(errno);
     316           0 :                 DBG_ERR("Failed to create ncalrpc directory '%s': %s\n",
     317             :                         lp_ncalrpc_dir(), strerror(errno));
     318           0 :                 goto out;
     319             :         }
     320             : 
     321         112 :         fd = create_pipe_sock(lp_ncalrpc_dir(), endpoint, 0755);
     322         112 :         if (fd == -1) {
     323           0 :                 status = map_nt_error_from_unix_common(errno);
     324           0 :                 DBG_ERR("Failed to create ncalrpc socket '%s/%s': %s\n",
     325             :                         lp_ncalrpc_dir(), endpoint, strerror(errno));
     326           0 :                 goto out;
     327             :         }
     328             : 
     329         112 :         DBG_DEBUG("Opened ncalrpc socket fd '%d' for '%s/%s'\n",
     330             :                   fd, lp_ncalrpc_dir(), endpoint);
     331             : 
     332         112 :         *out_fd = fd;
     333             : 
     334         112 :         return NT_STATUS_OK;
     335             : 
     336           0 : out:
     337           0 :         return status;
     338             : }
     339             : 
     340        1731 : NTSTATUS dcesrv_create_binding_sockets(
     341             :         struct dcerpc_binding *b,
     342             :         TALLOC_CTX *mem_ctx,
     343             :         size_t *pnum_fds,
     344             :         int **pfds)
     345             : {
     346        1731 :         enum dcerpc_transport_t transport = dcerpc_binding_get_transport(b);
     347        1731 :         size_t i, num_fds = 1;
     348        1731 :         int *fds = NULL;
     349           0 :         NTSTATUS status;
     350             : 
     351        1731 :         if ((transport == NCALRPC) || (transport == NCACN_NP)) {
     352        1635 :                 fds = talloc(mem_ctx, int);
     353        1635 :                 if (fds == NULL) {
     354           0 :                         return NT_STATUS_NO_MEMORY;
     355             :                 }
     356             :         }
     357             : 
     358        1731 :         switch(transport) {
     359         112 :         case NCALRPC:
     360         112 :                 status = dcesrv_create_ncalrpc_socket(b, fds);
     361         112 :                 break;
     362        1523 :         case NCACN_NP:
     363        1523 :                 status = dcesrv_create_ncacn_np_socket(b, fds);
     364        1523 :                 break;
     365          80 :         case NCACN_IP_TCP:
     366          80 :                 status = dcesrv_create_ncacn_ip_tcp_sockets(
     367             :                         b, talloc_tos(), &num_fds, &fds);
     368          80 :                 break;
     369          16 :         default:
     370          16 :                 status = NT_STATUS_NOT_SUPPORTED;
     371          16 :                 break;
     372             :         }
     373             : 
     374        1731 :         if (!NT_STATUS_IS_OK(status)) {
     375          16 :                 TALLOC_FREE(fds);
     376          16 :                 return status;
     377             :         }
     378             : 
     379        3510 :         for (i=0; i<num_fds; i++) {
     380        1795 :                 bool ok = smb_set_close_on_exec(fds[i]);
     381        1795 :                 if (!ok) {
     382           0 :                         status = map_nt_error_from_unix(errno);
     383           0 :                         break;
     384             :                 }
     385             :         }
     386        1715 :         if (i < num_fds) {
     387           0 :                 for (i=0; i<num_fds; i++) {
     388           0 :                         close(fds[i]);
     389             :                 }
     390           0 :                 TALLOC_FREE(fds);
     391           0 :                 return status;
     392             :         }
     393             : 
     394        1715 :         *pfds = fds;
     395        1715 :         *pnum_fds = num_fds;
     396        1715 :         return NT_STATUS_OK;
     397             : }
     398             : 
     399             : /* vim: set ts=8 sw=8 noet cindent syntax=c.doxygen: */

Generated by: LCOV version 1.14