LCOV - code coverage report
Current view: top level - source3/rpc_client - local_np.c (source / functions) Hit Total Coverage
Test: coverage report for master 98b443d9 Lines: 294 402 73.1 %
Date: 2024-05-31 13:13:24 Functions: 18 18 100.0 %

          Line data    Source code
       1             : /*
       2             :  *  Unix SMB/CIFS implementation.
       3             :  *
       4             :  *  This program is free software; you can redistribute it and/or modify
       5             :  *  it under the terms of the GNU General Public License as published by
       6             :  *  the Free Software Foundation; either version 3 of the License, or
       7             :  *  (at your option) any later version.
       8             :  *
       9             :  *  This program is distributed in the hope that it will be useful,
      10             :  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             :  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12             :  *  GNU General Public License for more details.
      13             :  *
      14             :  *  You should have received a copy of the GNU General Public License
      15             :  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
      16             :  */
      17             : 
      18             : #include "source3/include/includes.h"
      19             : #include <spawn.h>
      20             : #include "local_np.h"
      21             : #include "lib/async_req/async_sock.h"
      22             : #include "librpc/gen_ndr/ndr_named_pipe_auth.h"
      23             : #include "libcli/named_pipe_auth/npa_tstream.h"
      24             : #include "libcli/named_pipe_auth/tstream_u32_read.h"
      25             : #include "lib/util/tevent_unix.h"
      26             : #include "auth/auth_util.h"
      27             : #include "libcli/security/dom_sid.h"
      28             : #include "libcli/security/security_token.h"
      29             : #include "nsswitch/winbind_client.h"
      30             : 
      31             : /**
      32             :  * @file local_np.c
      33             :  *
      34             :  * Connect to a local named pipe by connecting to
      35             :  * samba-dcerpcd. Start samba-dcerpcd if it isn't
      36             :  * already running.
      37             :  */
      38             : 
      39             : extern bool override_logfile;
      40             : 
      41             : struct np_sock_connect_state {
      42             :         struct tevent_context *ev;
      43             :         struct samba_sockaddr addr;
      44             :         const struct named_pipe_auth_req *npa_req;
      45             :         struct named_pipe_auth_rep *npa_rep;
      46             : 
      47             :         DATA_BLOB npa_blob;
      48             :         struct iovec iov;
      49             : 
      50             :         int sock;
      51             :         struct tevent_req *subreq;
      52             :         struct tstream_context *transport;
      53             :         struct tstream_context *npa_stream;
      54             : };
      55             : 
      56             : static void np_sock_connect_cleanup(
      57             :         struct tevent_req *req, enum tevent_req_state req_state);
      58             : static void np_sock_connect_before(void *private_data);
      59             : static void np_sock_connect_after(void *private_data);
      60             : static void np_sock_connect_connected(struct tevent_req *subreq);
      61             : static void np_sock_connect_written(struct tevent_req *subreq);
      62             : static void np_sock_connect_read_done(struct tevent_req *subreq);
      63             : 
      64       48369 : static struct tevent_req *np_sock_connect_send(
      65             :         TALLOC_CTX *mem_ctx,
      66             :         struct tevent_context *ev,
      67             :         const char *sockpath,
      68             :         const struct named_pipe_auth_req *npa_req)
      69             : {
      70       48369 :         struct tevent_req *req = NULL;
      71       48369 :         struct np_sock_connect_state *state = NULL;
      72         620 :         size_t len;
      73         620 :         int ret;
      74         620 :         bool ok;
      75             : 
      76       48369 :         req = tevent_req_create(mem_ctx, &state, struct np_sock_connect_state);
      77       48369 :         if (req == NULL) {
      78           0 :                 return NULL;
      79             :         }
      80       48369 :         state->ev = ev;
      81       48369 :         state->npa_req = npa_req;
      82       48369 :         state->sock = -1;
      83       48369 :         state->addr.u.un.sun_family = AF_UNIX;
      84             : 
      85       48369 :         state->npa_rep = talloc_zero(state, struct named_pipe_auth_rep);
      86       48369 :         if (tevent_req_nomem(state->npa_rep, req)) {
      87           0 :                 return tevent_req_post(req, ev);
      88             :         }
      89             : 
      90       48369 :         tevent_req_set_cleanup_fn(req, np_sock_connect_cleanup);
      91             : 
      92       48369 :         state->addr.sa_socklen = sizeof(struct sockaddr_un);
      93       48369 :         len = strlcpy(state->addr.u.un.sun_path,
      94             :                       sockpath,
      95             :                       sizeof(state->addr.u.un.sun_path));
      96       48369 :         if (len >= sizeof(state->addr.u.un.sun_path)) {
      97           0 :                 tevent_req_error(req, ENAMETOOLONG);
      98           0 :                 return tevent_req_post(req, ev);
      99             :         }
     100             : 
     101       48369 :         state->sock = socket(AF_UNIX, SOCK_STREAM, 0);
     102       48369 :         if (state->sock == -1) {
     103           0 :                 tevent_req_error(req, errno);
     104           0 :                 return tevent_req_post(req, ev);
     105             :         }
     106             : 
     107       48369 :         ret = set_blocking(state->sock, true);
     108       48369 :         if (ret == -1) {
     109           0 :                 tevent_req_error(req, errno);
     110           0 :                 return tevent_req_post(req, ev);
     111             :         }
     112       48369 :         ok = set_close_on_exec(state->sock);
     113       48369 :         if (!ok) {
     114           0 :                 tevent_req_error(req, errno);
     115           0 :                 return tevent_req_post(req, ev);
     116             :         }
     117             : 
     118       96738 :         state->subreq = async_connect_send(
     119             :                 state,
     120             :                 ev,
     121       47749 :                 state->sock,
     122       48369 :                 &state->addr.u.sa,
     123       48369 :                 state->addr.sa_socklen,
     124             :                 np_sock_connect_before,
     125             :                 np_sock_connect_after,
     126             :                 NULL);
     127       48369 :         if (tevent_req_nomem(state->subreq, req)) {
     128           0 :                 return tevent_req_post(req, ev);
     129             :         }
     130       48369 :         tevent_req_set_callback(state->subreq, np_sock_connect_connected, req);
     131             : 
     132       48369 :         return req;
     133             : }
     134             : 
     135       96738 : static void np_sock_connect_cleanup(
     136             :         struct tevent_req *req, enum tevent_req_state req_state)
     137             : {
     138       96738 :         struct np_sock_connect_state *state = tevent_req_data(
     139             :                 req, struct np_sock_connect_state);
     140             : 
     141       96738 :         TALLOC_FREE(state->subreq);
     142       96738 :         TALLOC_FREE(state->transport);
     143             : 
     144       96738 :         if (state->sock != -1) {
     145         271 :                 close(state->sock);
     146         271 :                 state->sock = -1;
     147             :         }
     148       96738 : }
     149             : 
     150       48369 : static void np_sock_connect_before(void *private_data)
     151             : {
     152       48369 :         become_root();
     153       48369 : }
     154             : 
     155       48369 : static void np_sock_connect_after(void *private_data)
     156             : {
     157       48369 :         unbecome_root();
     158       48369 : }
     159             : 
     160       48369 : static void np_sock_connect_connected(struct tevent_req *subreq)
     161             : {
     162       48369 :         struct tevent_req *req = tevent_req_callback_data(
     163             :                 subreq, struct tevent_req);
     164       48369 :         struct np_sock_connect_state *state = tevent_req_data(
     165             :                 req, struct np_sock_connect_state);
     166         620 :         enum ndr_err_code ndr_err;
     167         620 :         int ret, err;
     168             : 
     169       48369 :         SMB_ASSERT(subreq == state->subreq);
     170             : 
     171       48369 :         ret = async_connect_recv(subreq, &err);
     172       48369 :         TALLOC_FREE(subreq);
     173       48369 :         state->subreq = NULL;
     174       48369 :         if (ret == -1) {
     175         271 :                 DBG_DEBUG("async_connect_recv returned %s\n", strerror(err));
     176         271 :                 tevent_req_error(req, err);
     177         271 :                 return;
     178             :         }
     179             : 
     180             :         /*
     181             :          * As a quick workaround for bug 15310 we have done the
     182             :          * connect in blocking mode (see np_sock_connect_send()). The
     183             :          * rest of our code expects a nonblocking socket, activate
     184             :          * this after the connect succeeded.
     185             :          */
     186       48098 :         ret = set_blocking(state->sock, false);
     187       48098 :         if (ret == -1) {
     188           0 :                 tevent_req_error(req, errno);
     189           0 :                 return;
     190             :         }
     191             : 
     192       48098 :         ret = tstream_bsd_existing_socket(
     193             :                 state, state->sock, &state->transport);
     194       48098 :         if (ret == -1) {
     195           0 :                 err = errno;
     196           0 :                 DBG_DEBUG("tstream_bsd_existing_socket failed: %s\n",
     197             :                           strerror(err));
     198           0 :                 tevent_req_error(req, err);
     199           0 :                 return;
     200             :         }
     201       48098 :         state->sock = -1;
     202             : 
     203       48718 :         ndr_err = ndr_push_struct_blob(
     204             :                 &state->npa_blob,
     205             :                 state,
     206       48098 :                 state->npa_req,
     207             :                 (ndr_push_flags_fn_t)ndr_push_named_pipe_auth_req);
     208       48098 :         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
     209           0 :                 DBG_DEBUG("ndr_push_struct_blob failed: %s\n",
     210             :                           ndr_errstr(ndr_err));
     211           0 :                 tevent_req_error(req, ndr_map_error2errno(ndr_err));
     212           0 :                 return;
     213             :         }
     214       48098 :         state->iov = (struct iovec) {
     215       48098 :                 .iov_base = state->npa_blob.data,
     216       48098 :                 .iov_len = state->npa_blob.length,
     217             :         };
     218             : 
     219       48718 :         subreq = tstream_writev_send(
     220       48098 :                 state, state->ev, state->transport, &state->iov, 1);
     221       48098 :         if (tevent_req_nomem(subreq, req)) {
     222           0 :                 return;
     223             :         }
     224       48098 :         tevent_req_set_callback(subreq, np_sock_connect_written, req);
     225             : }
     226             : 
     227       48098 : static void np_sock_connect_written(struct tevent_req *subreq)
     228             : {
     229       48098 :         struct tevent_req *req = tevent_req_callback_data(
     230             :                 subreq, struct tevent_req);
     231       48098 :         struct np_sock_connect_state *state = tevent_req_data(
     232             :                 req, struct np_sock_connect_state);
     233         620 :         int ret, err;
     234             : 
     235       48098 :         ret = tstream_writev_recv(subreq, &err);
     236       48098 :         TALLOC_FREE(subreq);
     237       48098 :         if (ret == -1) {
     238           0 :                 DBG_DEBUG("tstream_writev_recv returned %s\n", strerror(err));
     239           0 :                 tevent_req_error(req, err);
     240           0 :                 return;
     241             :         }
     242             : 
     243       48098 :         subreq = tstream_u32_read_send(
     244             :                 state, state->ev, 0x00FFFFFF, state->transport);
     245       48098 :         if (tevent_req_nomem(subreq, req)) {
     246           0 :                 return;
     247             :         }
     248       48098 :         tevent_req_set_callback(subreq, np_sock_connect_read_done, req);
     249             : }
     250             : 
     251       48098 : static void np_sock_connect_read_done(struct tevent_req *subreq)
     252             : {
     253       48098 :         struct tevent_req *req = tevent_req_callback_data(
     254             :                 subreq, struct tevent_req);
     255       48098 :         struct np_sock_connect_state *state = tevent_req_data(
     256             :                 req, struct np_sock_connect_state);
     257         620 :         DATA_BLOB in;
     258         620 :         int ret;
     259         620 :         enum ndr_err_code ndr_err;
     260             : 
     261       48098 :         ret = tstream_u32_read_recv(subreq, state, &in.data, &in.length);
     262       48098 :         TALLOC_FREE(subreq);
     263       48098 :         if (tevent_req_error(req, ret)) {
     264           0 :                 return;
     265             :         }
     266             : 
     267       48718 :         ndr_err = ndr_pull_struct_blob_all(
     268             :                 &in,
     269       47478 :                 state->npa_rep,
     270       48098 :                 state->npa_rep,
     271             :                 (ndr_pull_flags_fn_t)ndr_pull_named_pipe_auth_rep);
     272       48098 :         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
     273           0 :                 DBG_DEBUG("ndr_pull_named_pipe_auth_rep failed: %s\n",
     274             :                           ndr_errstr(ndr_err));
     275           0 :                 tevent_req_error(req, ndr_map_error2errno(ndr_err));
     276           0 :                 return;
     277             :         }
     278       48098 :         if (state->npa_rep->level != 8) {
     279           0 :                 DBG_DEBUG("npa level = %" PRIu32 ", expected 8\n",
     280             :                           state->npa_rep->level);
     281           0 :                 tevent_req_error(req, EIO);
     282           0 :                 return;
     283             :         }
     284             : 
     285       48098 :         ret = tstream_npa_existing_stream(state,
     286             :                                           &state->transport,
     287             :                                           state->npa_rep->info.info8.file_type,
     288             :                                           &state->npa_stream);
     289       48098 :         if (ret == -1) {
     290           0 :                 ret = errno;
     291           0 :                 DBG_DEBUG("tstream_npa_existing_stream failed: %s\n",
     292             :                           strerror(ret));
     293           0 :                 tevent_req_error(req, ret);
     294           0 :                 return;
     295             :         }
     296             : 
     297       48098 :         tevent_req_done(req);
     298             : }
     299             : 
     300       48369 : static int np_sock_connect_recv(
     301             :         struct tevent_req *req,
     302             :         TALLOC_CTX *mem_ctx,
     303             :         struct tstream_context **stream)
     304             : {
     305       48369 :         struct np_sock_connect_state *state = tevent_req_data(
     306             :                 req, struct np_sock_connect_state);
     307         620 :         int err;
     308             : 
     309       48369 :         if (tevent_req_is_unix_error(req, &err)) {
     310         271 :                 tevent_req_received(req);
     311         271 :                 return err;
     312             :         }
     313       48098 :         *stream = talloc_move(mem_ctx, &state->npa_stream);
     314       48098 :         tevent_req_received(req);
     315       48098 :         return 0;
     316             : }
     317             : 
     318             : struct start_rpc_host_state {
     319             :         int ready_fd;
     320             :         struct tevent_req *read_ready_req;
     321             : };
     322             : 
     323             : static void start_rpc_host_cleanup(
     324             :         struct tevent_req *req, enum tevent_req_state req_state);
     325             : static void start_rpc_host_ready(struct tevent_req *subreq);
     326             : 
     327             : /*
     328             :  * Start samba-dcerpcd and wait for it to report ready.
     329             :  */
     330         130 : static struct tevent_req *start_rpc_host_send(
     331             :         TALLOC_CTX *mem_ctx, struct tevent_context *ev)
     332             : {
     333         130 :         struct tevent_req *req = NULL, *subreq = NULL;
     334         130 :         struct start_rpc_host_state *state = NULL;
     335           0 :         int ret;
     336         130 :         int ready_fds[2] = { -1, -1 };
     337         130 :         char **argv = NULL;
     338           0 :         pid_t pid;
     339           0 :         bool ok;
     340             : 
     341         130 :         req = tevent_req_create(
     342             :                 mem_ctx, &state, struct start_rpc_host_state);
     343         130 :         if (req == NULL) {
     344           0 :                 return NULL;
     345             :         }
     346             : 
     347         130 :         ret = pipe(ready_fds);
     348         130 :         if (ret == -1) {
     349           0 :                 ret = errno;
     350           0 :                 DBG_DEBUG("pipe() failed: %s\n", strerror(ret));
     351           0 :                 goto fail;
     352             :         }
     353             : 
     354         130 :         ok = smb_set_close_on_exec(ready_fds[0]);
     355         130 :         if (!ok) {
     356           0 :                 ret = errno;
     357           0 :                 DBG_DEBUG("smb_set_close_on_exec failed: %s\n",
     358             :                           strerror(ret));
     359           0 :                 goto fail;
     360             :         }
     361             : 
     362         130 :         argv = str_list_make_empty(mem_ctx);
     363         130 :         str_list_add_printf(
     364             :                 &argv, "%s/samba-dcerpcd", get_dyn_SAMBA_LIBEXECDIR());
     365         130 :         if (!is_default_dyn_CONFIGFILE()) {
     366         130 :                 str_list_add_printf(
     367             :                         &argv, "--configfile=%s", get_dyn_CONFIGFILE());
     368             :         }
     369         130 :         str_list_add_printf(&argv, "--libexec-rpcds");
     370         130 :         str_list_add_printf(&argv, "--ready-signal-fd=%d", ready_fds[1]);
     371         130 :         str_list_add_printf(&argv, "--np-helper");
     372         130 :         str_list_add_printf(
     373             :                 &argv, "--debuglevel=%d", debuglevel_get_class(DBGC_RPC_SRV));
     374         130 :         if (!is_default_dyn_LOGFILEBASE()) {
     375          45 :                 str_list_add_printf(
     376             :                         &argv, "--log-basename=%s", get_dyn_LOGFILEBASE());
     377             :         }
     378         130 :         if (argv == NULL) {
     379           0 :                 errno = ENOMEM;
     380           0 :                 goto fail;
     381             :         }
     382             : 
     383         130 :         become_root();
     384         130 :         ret = posix_spawn(&pid, argv[0], NULL, NULL, argv, environ);
     385         130 :         unbecome_root();
     386         130 :         if (ret != 0) {
     387           0 :                 DBG_DEBUG("posix_spawn() failed: %s\n", strerror(ret));
     388           0 :                 goto fail;
     389             :         }
     390             : 
     391         130 :         state->ready_fd = ready_fds[0];
     392         130 :         ready_fds[0] = -1;
     393         130 :         tevent_req_set_cleanup_fn(req, start_rpc_host_cleanup);
     394             : 
     395         130 :         close(ready_fds[1]);
     396         130 :         ready_fds[1] = -1;
     397             : 
     398         130 :         subreq = read_packet_send(state, ev, state->ready_fd, 1, NULL, NULL);
     399         130 :         if (tevent_req_nomem(subreq, req)) {
     400           0 :                 return tevent_req_post(req, ev);
     401             :         }
     402         130 :         tevent_req_set_callback(subreq, start_rpc_host_ready, req);
     403         130 :         return req;
     404             : 
     405           0 : fail:
     406           0 :         if (ready_fds[0] != -1) {
     407           0 :                 close(ready_fds[0]);
     408           0 :                 ready_fds[0] = -1;
     409             :         }
     410           0 :         if (ready_fds[1] != -1) {
     411           0 :                 close(ready_fds[1]);
     412           0 :                 ready_fds[1] = -1;
     413             :         }
     414           0 :         tevent_req_error(req, ret);
     415           0 :         return tevent_req_post(req, ev);
     416             : }
     417             : 
     418         260 : static void start_rpc_host_cleanup(
     419             :         struct tevent_req *req, enum tevent_req_state req_state)
     420             : {
     421         260 :         struct start_rpc_host_state *state = tevent_req_data(
     422             :                 req, struct start_rpc_host_state);
     423             : 
     424         260 :         if (state->ready_fd != -1) {
     425           0 :                 close(state->ready_fd);
     426           0 :                 state->ready_fd = -1;
     427             :         }
     428         260 : }
     429             : 
     430         130 : static void start_rpc_host_ready(struct tevent_req *subreq)
     431             : {
     432         130 :         struct tevent_req *req = tevent_req_callback_data(
     433             :                 subreq, struct tevent_req);
     434         130 :         struct start_rpc_host_state *state = tevent_req_data(
     435             :                 req, struct start_rpc_host_state);
     436           0 :         uint8_t *buf;
     437           0 :         int err;
     438           0 :         ssize_t nread;
     439             : 
     440         130 :         nread = read_packet_recv(subreq, state, &buf, &err);
     441         130 :         TALLOC_FREE(subreq);
     442         130 :         if (nread == -1) {
     443           0 :                 tevent_req_error(req, err);
     444           0 :                 return;
     445             :         }
     446             : 
     447         130 :         close(state->ready_fd);
     448         130 :         state->ready_fd = -1;
     449             : 
     450         130 :         tevent_req_done(req);
     451             : }
     452             : 
     453         130 : static int start_rpc_host_recv(struct tevent_req *req)
     454             : {
     455         130 :         return tevent_req_simple_recv_unix(req);
     456             : }
     457             : 
     458             : struct local_np_connect_state {
     459             :         struct tevent_context *ev;
     460             :         const char *socketpath;
     461             :         struct named_pipe_auth_req *npa_req;
     462             :         struct tstream_context *npa_stream;
     463             : };
     464             : 
     465             : static void local_np_connect_connected(struct tevent_req *subreq);
     466             : static void local_np_connect_started(struct tevent_req *subreq);
     467             : static void local_np_connect_retried(struct tevent_req *subreq);
     468             : 
     469             : /**
     470             :  * @brief Async connect to a local named pipe RPC interface
     471             :  *
     472             :  * Start "samba-dcerpcd" on demand if it does not exist
     473             :  *
     474             :  * @param[in] mem_ctx  The memory context to use.
     475             :  * @param[in] ev       The tevent context to use.
     476             :  *
     477             :  * @param[in] pipename The raw pipename to connect to without path
     478             :  * @param[in] remote_client_name The client name to transmit
     479             :  * @param[in] remote_client_addr The client addr to transmit
     480             :  * @param[in] local_server_name The server name to transmit
     481             :  * @param[in] local_server_addr The server addr to transmit
     482             :  * @param[in] session_info The authorization info to use
     483             :  * @param[in] need_idle_server Does this need to be an exclusive server?
     484             :  * @return The tevent_req that was started
     485             :  */
     486             : 
     487       48249 : struct tevent_req *local_np_connect_send(
     488             :         TALLOC_CTX *mem_ctx,
     489             :         struct tevent_context *ev,
     490             :         const char *pipename,
     491             :         enum dcerpc_transport_t transport,
     492             :         const char *remote_client_name,
     493             :         const struct tsocket_address *remote_client_addr,
     494             :         const char *local_server_name,
     495             :         const struct tsocket_address *local_server_addr,
     496             :         const struct auth_session_info *session_info,
     497             :         bool need_idle_server)
     498             : {
     499       48249 :         struct tevent_req *req = NULL, *subreq = NULL;
     500       48249 :         struct local_np_connect_state *state = NULL;
     501       48249 :         struct named_pipe_auth_req_info8 *i8 = NULL;
     502       48249 :         const char *socket_dir = NULL;
     503       48249 :         char *lower_case_pipename = NULL;
     504       48249 :         struct dom_sid npa_sid = global_sid_Samba_NPA_Flags;
     505       48249 :         uint32_t npa_flags = 0;
     506       48249 :         struct security_token *token = NULL;
     507         620 :         NTSTATUS status;
     508         620 :         size_t num_npa_sids;
     509         620 :         bool ok;
     510             : 
     511       48249 :         req = tevent_req_create(
     512             :                 mem_ctx, &state, struct local_np_connect_state);
     513       48249 :         if (req == NULL) {
     514           0 :                 return NULL;
     515             :         }
     516       48249 :         state->ev = ev;
     517             : 
     518         620 :         num_npa_sids =
     519       48249 :                 security_token_count_flag_sids(session_info->security_token,
     520             :                                                &npa_sid,
     521             :                                                1,
     522             :                                                NULL);
     523       48249 :         if (num_npa_sids != 0) {
     524           0 :                 DBG_ERR("ERROR: %zu NPA Flags SIDs have already been "
     525             :                         "detected in the security token!\n",
     526             :                         num_npa_sids);
     527           0 :                 tevent_req_error(req, EACCES);
     528           0 :                 return tevent_req_post(req, ev);
     529             :         }
     530             : 
     531       48249 :         socket_dir = lp_parm_const_string(
     532             :                 GLOBAL_SECTION_SNUM, "external_rpc_pipe", "socket_dir",
     533             :                 lp_ncalrpc_dir());
     534       48249 :         if (socket_dir == NULL) {
     535           0 :                 DBG_DEBUG("external_rpc_pipe:socket_dir not set\n");
     536           0 :                 tevent_req_error(req, EINVAL);
     537           0 :                 return tevent_req_post(req, ev);
     538             :         }
     539             : 
     540       48249 :         lower_case_pipename = strlower_talloc(state, pipename);
     541       48249 :         if (tevent_req_nomem(lower_case_pipename, req)) {
     542           0 :                 return tevent_req_post(req, ev);
     543             :         }
     544             : 
     545             :         /*
     546             :          * Ensure we cannot process a path that exits
     547             :          * the socket_dir.
     548             :          */
     549       48249 :         if (ISDOTDOT(lower_case_pipename) ||
     550       48249 :             (strchr(lower_case_pipename, '/')!=NULL))
     551             :         {
     552          10 :                 DBG_DEBUG("attempt to connect to invalid pipe pathname %s\n",
     553             :                         lower_case_pipename);
     554          10 :                 tevent_req_error(req, ENOENT);
     555          10 :                 return tevent_req_post(req, ev);
     556             :         }
     557             : 
     558       48239 :         state->socketpath = talloc_asprintf(
     559             :                 state, "%s/np/%s", socket_dir, lower_case_pipename);
     560       48239 :         if (tevent_req_nomem(state->socketpath, req)) {
     561           0 :                 return tevent_req_post(req, ev);
     562             :         }
     563       48239 :         TALLOC_FREE(lower_case_pipename);
     564             : 
     565       48239 :         state->npa_req = talloc_zero(state, struct named_pipe_auth_req);
     566       48239 :         if (tevent_req_nomem(state->npa_req, req)) {
     567           0 :                 return tevent_req_post(req, ev);
     568             :         }
     569       48239 :         state->npa_req->level = 8;
     570             : 
     571       48239 :         i8 = &state->npa_req->info.info8;
     572             : 
     573       48239 :         i8->transport = transport;
     574             : 
     575             :         /* we don't have "int" in IDL, make sure we don't overflow */
     576       48239 :         SMB_ASSERT(i8->transport == transport);
     577             : 
     578       48239 :         if (remote_client_name == NULL) {
     579       48239 :                 remote_client_name = get_myname(state->npa_req);
     580       48239 :                 if (remote_client_name == NULL) {
     581           0 :                         tevent_req_error(req, errno);
     582           0 :                         return tevent_req_post(req, ev);
     583             :                 }
     584             :         }
     585       48239 :         i8->remote_client_name = remote_client_name;
     586             : 
     587       48239 :         if (remote_client_addr == NULL) {
     588           0 :                 struct tsocket_address *addr = NULL;
     589           0 :                 int ret = tsocket_address_inet_from_strings(
     590             :                         state->npa_req, "ip", NULL, 0, &addr);
     591           0 :                 if (ret != 0) {
     592           0 :                         tevent_req_error(req, errno);
     593           0 :                         return tevent_req_post(req, ev);
     594             :                 }
     595           0 :                 remote_client_addr = addr;
     596             :         }
     597       48859 :         i8->remote_client_addr =
     598       48239 :                 tsocket_address_inet_addr_string(remote_client_addr,
     599       48239 :                                                  state->npa_req);
     600       48239 :         if (i8->remote_client_addr == NULL) {
     601           0 :                 tevent_req_error(req, errno);
     602           0 :                 return tevent_req_post(req, ev);
     603             :         }
     604       48239 :         i8->remote_client_port = tsocket_address_inet_port(remote_client_addr);
     605             : 
     606       48239 :         if (local_server_name == NULL) {
     607       48239 :                 local_server_name = remote_client_name;
     608             :         }
     609       48239 :         i8->local_server_name = local_server_name;
     610             : 
     611       48239 :         if (local_server_addr == NULL) {
     612       30587 :                 struct tsocket_address *addr = NULL;
     613       30587 :                 int ret = tsocket_address_inet_from_strings(
     614             :                         state->npa_req, "ip", NULL, 0, &addr);
     615       30587 :                 if (ret != 0) {
     616           0 :                         tevent_req_error(req, errno);
     617           0 :                         return tevent_req_post(req, ev);
     618             :                 }
     619       30587 :                 local_server_addr = addr;
     620             :         }
     621       48859 :         i8->local_server_addr =
     622       48239 :                 tsocket_address_inet_addr_string(local_server_addr,
     623       48239 :                                                  state->npa_req);
     624       48239 :         if (i8->local_server_addr == NULL) {
     625           0 :                 tevent_req_error(req, errno);
     626           0 :                 return tevent_req_post(req, ev);
     627             :         }
     628       48239 :         i8->local_server_port = tsocket_address_inet_port(local_server_addr);
     629             : 
     630       48239 :         i8->session_info = talloc_zero(state->npa_req,
     631             :                                        struct auth_session_info_transport);
     632       48239 :         if (tevent_req_nomem(i8->session_info, req)) {
     633           0 :                 return tevent_req_post(req, ev);
     634             :         }
     635             : 
     636       96478 :         i8->session_info->session_info =
     637       48239 :                 copy_session_info(i8->session_info, session_info);
     638       48239 :         if (tevent_req_nomem(i8->session_info->session_info, req)) {
     639           0 :                 return tevent_req_post(req, ev);
     640             :         }
     641             : 
     642       48239 :         if (need_idle_server) {
     643       30671 :                 npa_flags |= SAMBA_NPA_FLAGS_NEED_IDLE;
     644             :         }
     645             : 
     646       48239 :         ok = winbind_env_set();
     647       48239 :         if (ok) {
     648           0 :                 npa_flags |= SAMBA_NPA_FLAGS_WINBIND_OFF;
     649             :         }
     650             : 
     651       48239 :         ok = sid_append_rid(&npa_sid, npa_flags);
     652       48239 :         if (!ok) {
     653           0 :                 tevent_req_error(req, EINVAL);
     654           0 :                 return tevent_req_post(req, ev);
     655             :         }
     656             : 
     657       48239 :         token = i8->session_info->session_info->security_token;
     658             : 
     659       48239 :         status = add_sid_to_array_unique(token,
     660             :                                          &npa_sid,
     661             :                                          &token->sids,
     662             :                                          &token->num_sids);
     663       48239 :         if (!NT_STATUS_IS_OK(status)) {
     664           0 :                 tevent_req_oom(req);
     665           0 :                 return tevent_req_post(req, ev);
     666             :         }
     667             : 
     668       48859 :         subreq = np_sock_connect_send(
     669       48239 :                 state, state->ev, state->socketpath, state->npa_req);
     670       48239 :         if (tevent_req_nomem(subreq, req)) {
     671           0 :                 return tevent_req_post(req, ev);
     672             :         }
     673       48239 :         tevent_req_set_callback(subreq, local_np_connect_connected, req);
     674             : 
     675       48239 :         return req;
     676             : }
     677             : 
     678       48239 : static void local_np_connect_connected(struct tevent_req *subreq)
     679             : {
     680       48239 :         struct tevent_req *req = tevent_req_callback_data(
     681             :                 subreq, struct tevent_req);
     682       48239 :         struct local_np_connect_state *state = tevent_req_data(
     683             :                 req, struct local_np_connect_state);
     684         620 :         int ret;
     685             : 
     686       48239 :         ret = np_sock_connect_recv(subreq, state, &state->npa_stream);
     687       48239 :         TALLOC_FREE(subreq);
     688             : 
     689       48239 :         if (ret == 0) {
     690       48039 :                 tevent_req_done(req);
     691       48039 :                 return;
     692             :         }
     693             : 
     694         200 :         DBG_DEBUG("np_sock_connect failed: %s\n", strerror(ret));
     695             : 
     696         200 :         if (!lp_rpc_start_on_demand_helpers()) {
     697             :                 /*
     698             :                  * samba-dcerpcd should already be started in
     699             :                  * daemon/standalone mode when "rpc start on demand
     700             :                  * helpers = false". We are prohibited from starting
     701             :                  * on demand as a named-pipe helper.
     702             :                  */
     703          70 :                 DBG_ERR("Can't connect to a running samba-dcerpcd. smb.conf "
     704             :                         "config prohibits starting as named pipe helper as "
     705             :                         "the [global] section contains "
     706             :                         "\"rpc start on demand helpers = false\".\n");
     707          70 :                 tevent_req_error(req, ret);
     708          70 :                 return;
     709             :         }
     710             : 
     711             :         /*
     712             :          * samba-dcerpcd isn't running. We need to start it.
     713             :          * Note if it doesn't start we treat this as a fatal
     714             :          * error for connecting to the named pipe and don't
     715             :          * keep trying to restart for this connection.
     716             :          */
     717         130 :         subreq = start_rpc_host_send(state, state->ev);
     718         130 :         if (tevent_req_nomem(subreq, req)) {
     719           0 :                 return;
     720             :         }
     721         130 :         tevent_req_set_callback(subreq, local_np_connect_started, req);
     722             : }
     723             : 
     724         130 : static void local_np_connect_started(struct tevent_req *subreq)
     725             : {
     726         130 :         struct tevent_req *req = tevent_req_callback_data(
     727             :                 subreq, struct tevent_req);
     728         130 :         struct local_np_connect_state *state = tevent_req_data(
     729             :                 req, struct local_np_connect_state);
     730           0 :         int ret;
     731             : 
     732         130 :         ret = start_rpc_host_recv(subreq);
     733         130 :         TALLOC_FREE(subreq);
     734         130 :         if (tevent_req_error(req, ret)) {
     735           0 :                 DBG_DEBUG("start_rpc_host_recv failed: %s\n",
     736             :                           strerror(ret));
     737           0 :                 return;
     738             :         }
     739             : 
     740         130 :         subreq = np_sock_connect_send(
     741         130 :                 state, state->ev, state->socketpath, state->npa_req);
     742         130 :         if (tevent_req_nomem(subreq, req)) {
     743           0 :                 return;
     744             :         }
     745         130 :         tevent_req_set_callback(subreq, local_np_connect_retried, req);
     746             : }
     747             : 
     748         130 : static void local_np_connect_retried(struct tevent_req *subreq)
     749             : {
     750         130 :         struct tevent_req *req = tevent_req_callback_data(
     751             :                 subreq, struct tevent_req);
     752         130 :         struct local_np_connect_state *state = tevent_req_data(
     753             :                 req, struct local_np_connect_state);
     754           0 :         int ret;
     755             : 
     756         130 :         ret = np_sock_connect_recv(subreq, state, &state->npa_stream);
     757         130 :         TALLOC_FREE(subreq);
     758         130 :         if (tevent_req_error(req, ret)) {
     759          71 :                 return;
     760             :         }
     761          59 :         tevent_req_done(req);
     762             : }
     763             : 
     764             : /**
     765             :  * @brief Receive handle to a local named pipe RPC interface
     766             :  *
     767             :  * @param[in] req The tevent_req that started the operation
     768             :  * @param[in] ev      The tevent context to use.
     769             :  * @param[in] mem_ctx The memory context to put pstream on
     770             :  * @param[out] pstream The established connection to the RPC server
     771             :  *
     772             :  * @return 0/errno
     773             :  */
     774             : 
     775       48249 : int local_np_connect_recv(
     776             :         struct tevent_req *req,
     777             :         TALLOC_CTX *mem_ctx,
     778             :         struct tstream_context **pstream)
     779             : {
     780       48249 :         struct local_np_connect_state *state = tevent_req_data(
     781             :                 req, struct local_np_connect_state);
     782         620 :         int err;
     783             : 
     784       48249 :         if (tevent_req_is_unix_error(req, &err)) {
     785         151 :                 tevent_req_received(req);
     786         151 :                 return err;
     787             :         }
     788             : 
     789       48098 :         *pstream = talloc_move(mem_ctx, &state->npa_stream);
     790       48098 :         return 0;
     791             : }
     792             : 
     793             : /**
     794             :  * @brief Sync connect to a local named pipe RPC interface
     795             :  *
     796             :  * Start "samba-dcerpcd" on demand if it does not exist
     797             :  *
     798             :  * @param[in] pipename The raw pipename to connect to without path
     799             :  * @param[in] remote_client_name The client name to transmit
     800             :  * @param[in] remote_client_addr The client addr to transmit
     801             :  * @param[in] local_server_name The server name to transmit
     802             :  * @param[in] local_server_addr The server addr to transmit
     803             :  * @param[in] session_info The authorization info to use
     804             :  * @param[in] need_idle_server Does this need to be an exclusive server?
     805             :  * @param[in] mem_ctx  The memory context to use.
     806             :  * @param[out] pstream The established connection to the RPC server
     807             :  * @return 0/errno
     808             :  */
     809             : 
     810       48249 : int local_np_connect(
     811             :         const char *pipename,
     812             :         enum dcerpc_transport_t transport,
     813             :         const char *remote_client_name,
     814             :         const struct tsocket_address *remote_client_addr,
     815             :         const char *local_server_name,
     816             :         const struct tsocket_address *local_server_addr,
     817             :         const struct auth_session_info *session_info,
     818             :         bool need_idle_server,
     819             :         TALLOC_CTX *mem_ctx,
     820             :         struct tstream_context **pstream)
     821             : {
     822       48249 :         struct tevent_context *ev = NULL;
     823       48249 :         struct tevent_req *req = NULL;
     824       48249 :         int ret = ENOMEM;
     825             : 
     826       48249 :         ev = samba_tevent_context_init(mem_ctx);
     827       48249 :         if (ev == NULL) {
     828           0 :                 goto fail;
     829             :         }
     830       48249 :         req = local_np_connect_send(
     831             :                 ev,
     832             :                 ev,
     833             :                 pipename,
     834             :                 transport,
     835             :                 remote_client_name,
     836             :                 remote_client_addr,
     837             :                 local_server_name,
     838             :                 local_server_addr,
     839             :                 session_info,
     840             :                 need_idle_server);
     841       48249 :         if (req == NULL) {
     842           0 :                 goto fail;
     843             :         }
     844       48249 :         if (!tevent_req_poll_unix(req, ev, &ret)) {
     845           0 :                 goto fail;
     846             :         }
     847       48249 :         ret = local_np_connect_recv(req, mem_ctx, pstream);
     848       48249 :  fail:
     849       48249 :         TALLOC_FREE(req);
     850       48249 :         TALLOC_FREE(ev);
     851       48249 :         return ret;
     852             : }

Generated by: LCOV version 1.14