Coverage Report

Created: 2026-07-25 07:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/samba/source3/lib/netapi/cm.c
Line
Count
Source
1
/*
2
 *  Unix SMB/CIFS implementation.
3
 *  NetApi Support
4
 *  Copyright (C) Guenther Deschner 2008
5
 *
6
 *  This program is free software; you can redistribute it and/or modify
7
 *  it under the terms of the GNU General Public License as published by
8
 *  the Free Software Foundation; either version 3 of the License, or
9
 *  (at your option) any later version.
10
 *
11
 *  This program is distributed in the hope that it will be useful,
12
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 *  GNU General Public License for more details.
15
 *
16
 *  You should have received a copy of the GNU General Public License
17
 *  along with this program; if not, see <http://www.gnu.org/licenses/>.
18
 */
19
20
#include "includes.h"
21
22
#include "lib/netapi/netapi.h"
23
#include "lib/netapi/netapi_private.h"
24
#include "source3/include/client.h"
25
#include "source3/libsmb/proto.h"
26
#include "rpc_client/cli_pipe.h"
27
#include "../libcli/smb/smbXcli_base.h"
28
29
/********************************************************************
30
********************************************************************/
31
32
struct client_ipc_connection {
33
  struct client_ipc_connection *prev, *next;
34
  struct cli_state *cli;
35
  struct client_pipe_connection *pipe_connections;
36
};
37
38
struct client_pipe_connection {
39
  struct client_pipe_connection *prev, *next;
40
  struct rpc_pipe_client *pipe;
41
};
42
43
/********************************************************************
44
********************************************************************/
45
46
static struct client_ipc_connection *ipc_cm_find(
47
  struct libnetapi_private_ctx *priv_ctx, const char *server_name)
48
0
{
49
0
  struct client_ipc_connection *p;
50
51
0
  for (p = priv_ctx->ipc_connections; p; p = p->next) {
52
0
    const char *remote_name = smbXcli_conn_remote_name(p->cli->conn);
53
54
0
    if (strequal(remote_name, server_name)) {
55
0
      return p;
56
0
    }
57
0
  }
58
59
0
  return NULL;
60
0
}
61
62
/********************************************************************
63
********************************************************************/
64
65
static WERROR libnetapi_open_ipc_connection(struct libnetapi_ctx *ctx,
66
              const char *server_name,
67
              struct client_ipc_connection **pp)
68
0
{
69
0
  struct libnetapi_private_ctx *priv_ctx;
70
0
  struct cli_state *cli_ipc = NULL;
71
0
  struct client_ipc_connection *p;
72
0
  NTSTATUS status;
73
0
  const char *username = NULL;
74
0
  const char *password = NULL;
75
0
  NET_API_STATUS rc;
76
0
  enum credentials_use_kerberos krb5_state;
77
0
  struct smb_transports ts =
78
0
    smb_transports_parse("client smb transports",
79
0
             lp_client_smb_transports());
80
81
0
  if (!ctx || !pp || !server_name) {
82
0
    return WERR_INVALID_PARAMETER;
83
0
  }
84
85
0
  priv_ctx = (struct libnetapi_private_ctx *)ctx->private_data;
86
87
0
  p = ipc_cm_find(priv_ctx, server_name);
88
0
  if (p) {
89
0
    *pp = p;
90
0
    return WERR_OK;
91
0
  }
92
93
0
  rc = libnetapi_get_username(ctx, &username);
94
0
  if (rc != 0) {
95
0
    return WERR_INTERNAL_ERROR;
96
0
  }
97
98
0
  rc = libnetapi_get_password(ctx, &password);
99
0
  if (rc != 0) {
100
0
    return WERR_INTERNAL_ERROR;
101
0
  }
102
103
0
  if (password == NULL) {
104
0
    cli_credentials_set_cmdline_callbacks(ctx->creds);
105
0
  }
106
107
0
  krb5_state = cli_credentials_get_kerberos_state(ctx->creds);
108
109
0
  if (username != NULL && username[0] != '\0' &&
110
0
      password != NULL && password[0] != '\0' &&
111
0
      krb5_state == CRED_USE_KERBEROS_REQUIRED) {
112
0
    cli_credentials_set_kerberos_state(ctx->creds,
113
0
               CRED_USE_KERBEROS_DESIRED,
114
0
               CRED_SPECIFIED);
115
0
  }
116
117
0
  status = cli_cm_open(ctx, NULL,
118
0
           server_name, "IPC$",
119
0
           ctx->creds,
120
0
           NULL, &ts, 0x20, &cli_ipc);
121
0
  if (!NT_STATUS_IS_OK(status)) {
122
0
    cli_ipc = NULL;
123
0
  }
124
125
0
  if (!cli_ipc) {
126
0
    libnetapi_set_error_string(ctx,
127
0
      "Failed to connect to IPC$ share on %s", server_name);
128
0
    return WERR_CAN_NOT_COMPLETE;
129
0
  }
130
131
0
  p = talloc_zero(ctx, struct client_ipc_connection);
132
0
  if (p == NULL) {
133
0
    return WERR_NOT_ENOUGH_MEMORY;
134
0
  }
135
136
0
  p->cli = cli_ipc;
137
0
  DLIST_ADD(priv_ctx->ipc_connections, p);
138
139
0
  *pp = p;
140
141
0
  return WERR_OK;
142
0
}
143
144
/********************************************************************
145
********************************************************************/
146
147
WERROR libnetapi_shutdown_cm(struct libnetapi_ctx *ctx)
148
0
{
149
0
  struct libnetapi_private_ctx *priv_ctx =
150
0
    (struct libnetapi_private_ctx *)ctx->private_data;
151
0
  struct client_ipc_connection *p;
152
153
0
  for (p = priv_ctx->ipc_connections; p; p = p->next) {
154
0
    cli_shutdown(p->cli);
155
0
  }
156
157
0
  return WERR_OK;
158
0
}
159
160
/********************************************************************
161
********************************************************************/
162
163
static NTSTATUS pipe_cm_find(struct client_ipc_connection *ipc,
164
           const struct ndr_interface_table *table,
165
           struct rpc_pipe_client **presult)
166
0
{
167
0
  struct client_pipe_connection *p;
168
169
0
  for (p = ipc->pipe_connections; p; p = p->next) {
170
0
    struct dcerpc_binding_handle *bh = NULL;
171
0
    const struct dcerpc_binding *bd = NULL;
172
0
    const char *ipc_remote_name;
173
0
    struct ndr_syntax_id syntax;
174
175
0
    if (!rpccli_is_connected(p->pipe)) {
176
0
      return NT_STATUS_PIPE_EMPTY;
177
0
    }
178
179
0
    ipc_remote_name = smbXcli_conn_remote_name(ipc->cli->conn);
180
181
0
    if (!strequal(ipc_remote_name, p->pipe->desthost)) {
182
0
      continue;
183
0
    }
184
185
0
    bh = p->pipe->binding_handle;
186
0
    bd = dcerpc_binding_handle_get_binding(bh);
187
0
    syntax = dcerpc_binding_get_abstract_syntax(bd);
188
189
0
    if (ndr_syntax_id_equal(&syntax, &table->syntax_id)) {
190
0
      *presult = p->pipe;
191
0
      return NT_STATUS_OK;
192
0
    }
193
0
  }
194
195
0
  return NT_STATUS_PIPE_NOT_AVAILABLE;
196
0
}
197
198
/********************************************************************
199
********************************************************************/
200
201
static NTSTATUS pipe_cm_connect(TALLOC_CTX *mem_ctx,
202
        struct client_ipc_connection *ipc,
203
        const struct ndr_interface_table *table,
204
        struct rpc_pipe_client **presult)
205
0
{
206
0
  struct client_pipe_connection *p;
207
0
  NTSTATUS status;
208
209
0
  p = talloc_zero_array(mem_ctx, struct client_pipe_connection, 1);
210
0
  if (!p) {
211
0
    return NT_STATUS_NO_MEMORY;
212
0
  }
213
214
0
  status = cli_rpc_pipe_open_noauth(ipc->cli, table, &p->pipe);
215
0
  if (!NT_STATUS_IS_OK(status)) {
216
0
    TALLOC_FREE(p);
217
0
    return status;
218
0
  }
219
220
0
  DLIST_ADD(ipc->pipe_connections, p);
221
222
0
  *presult = p->pipe;
223
0
  return NT_STATUS_OK;
224
0
}
225
226
/********************************************************************
227
********************************************************************/
228
229
static NTSTATUS pipe_cm_open(TALLOC_CTX *ctx,
230
           struct client_ipc_connection *ipc,
231
           const struct ndr_interface_table *table,
232
           struct rpc_pipe_client **presult)
233
0
{
234
0
  if (NT_STATUS_IS_OK(pipe_cm_find(ipc, table, presult))) {
235
0
    return NT_STATUS_OK;
236
0
  }
237
238
0
  return pipe_cm_connect(ctx, ipc, table, presult);
239
0
}
240
241
/********************************************************************
242
********************************************************************/
243
244
WERROR libnetapi_open_pipe(struct libnetapi_ctx *ctx,
245
         const char *server_name,
246
         const struct ndr_interface_table *table,
247
         struct rpc_pipe_client **presult)
248
0
{
249
0
  struct rpc_pipe_client *result = NULL;
250
0
  NTSTATUS status;
251
0
  WERROR werr;
252
0
  struct client_ipc_connection *ipc = NULL;
253
254
0
  if (!presult) {
255
0
    return WERR_INVALID_PARAMETER;
256
0
  }
257
258
0
  werr = libnetapi_open_ipc_connection(ctx, server_name, &ipc);
259
0
  if (!W_ERROR_IS_OK(werr)) {
260
0
    return werr;
261
0
  }
262
263
0
  status = pipe_cm_open(ctx, ipc, table, &result);
264
0
  if (!NT_STATUS_IS_OK(status)) {
265
0
    libnetapi_set_error_string(ctx, "failed to open PIPE %s: %s",
266
0
      table->name,
267
0
      get_friendly_nt_error_msg(status));
268
0
    return WERR_NERR_DESTNOTFOUND;
269
0
  }
270
271
0
  *presult = result;
272
273
0
  return WERR_OK;
274
0
}
275
276
/********************************************************************
277
********************************************************************/
278
279
WERROR libnetapi_get_binding_handle(struct libnetapi_ctx *ctx,
280
            const char *server_name,
281
            const struct ndr_interface_table *table,
282
            struct dcerpc_binding_handle **binding_handle)
283
0
{
284
0
  struct rpc_pipe_client *pipe_cli;
285
0
  WERROR result;
286
287
0
  *binding_handle = NULL;
288
289
0
  result = libnetapi_open_pipe(ctx, server_name, table, &pipe_cli);
290
0
  if (!W_ERROR_IS_OK(result)) {
291
0
    return result;
292
0
  }
293
294
0
  *binding_handle = pipe_cli->binding_handle;
295
296
0
  return WERR_OK;
297
0
}