bb5d6b234a52d949b3fe4cb5cbbc3741c15e2232
[mat/samba.git] / source3 / lib / netapi / cm.c
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 #include "auth_info.h"
22
23 #include "lib/netapi/netapi.h"
24 #include "lib/netapi/netapi_private.h"
25 #include "libsmb/libsmb.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 {
49         struct client_ipc_connection *p;
50
51         for (p = priv_ctx->ipc_connections; p; p = p->next) {
52                 const char *remote_name = smbXcli_conn_remote_name(p->cli->conn);
53
54                 if (strequal(remote_name, server_name)) {
55                         return p;
56                 }
57         }
58
59         return NULL;
60 }
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 {
69         struct libnetapi_private_ctx *priv_ctx;
70         struct user_auth_info *auth_info = NULL;
71         struct cli_state *cli_ipc = NULL;
72         struct client_ipc_connection *p;
73         NTSTATUS status;
74
75         if (!ctx || !pp || !server_name) {
76                 return WERR_INVALID_PARAM;
77         }
78
79         priv_ctx = (struct libnetapi_private_ctx *)ctx->private_data;
80
81         p = ipc_cm_find(priv_ctx, server_name);
82         if (p) {
83                 *pp = p;
84                 return WERR_OK;
85         }
86
87         auth_info = user_auth_info_init(ctx);
88         if (!auth_info) {
89                 return WERR_NOMEM;
90         }
91         auth_info->signing_state = SMB_SIGNING_DEFAULT;
92         set_cmdline_auth_info_use_kerberos(auth_info, ctx->use_kerberos);
93         set_cmdline_auth_info_username(auth_info, ctx->username);
94         if (ctx->password) {
95                 set_cmdline_auth_info_password(auth_info, ctx->password);
96         } else {
97                 set_cmdline_auth_info_getpass(auth_info);
98         }
99
100         if (ctx->username && ctx->username[0] &&
101             ctx->password && ctx->password[0] &&
102             ctx->use_kerberos) {
103                 set_cmdline_auth_info_fallback_after_kerberos(auth_info, true);
104         }
105
106         if (ctx->use_ccache) {
107                 set_cmdline_auth_info_use_ccache(auth_info, true);
108         }
109
110         status = cli_cm_open(ctx, NULL,
111                              server_name, "IPC$",
112                              auth_info,
113                              false, false,
114                              lp_cli_maxprotocol(),
115                              0, 0x20, &cli_ipc);
116         if (NT_STATUS_IS_OK(status)) {
117                 cli_set_username(cli_ipc, ctx->username);
118                 cli_set_password(cli_ipc, ctx->password);
119                 cli_set_domain(cli_ipc, ctx->workgroup);
120         } else {
121                 cli_ipc = NULL;
122         }
123         TALLOC_FREE(auth_info);
124
125         if (!cli_ipc) {
126                 libnetapi_set_error_string(ctx,
127                         "Failed to connect to IPC$ share on %s", server_name);
128                 return WERR_CAN_NOT_COMPLETE;
129         }
130
131         p = talloc_zero(ctx, struct client_ipc_connection);
132         if (p == NULL) {
133                 return WERR_NOMEM;
134         }
135
136         p->cli = cli_ipc;
137         DLIST_ADD(priv_ctx->ipc_connections, p);
138
139         *pp = p;
140
141         return WERR_OK;
142 }
143
144 /********************************************************************
145 ********************************************************************/
146
147 WERROR libnetapi_shutdown_cm(struct libnetapi_ctx *ctx)
148 {
149         struct libnetapi_private_ctx *priv_ctx =
150                 (struct libnetapi_private_ctx *)ctx->private_data;
151         struct client_ipc_connection *p;
152
153         for (p = priv_ctx->ipc_connections; p; p = p->next) {
154                 cli_shutdown(p->cli);
155         }
156
157         return WERR_OK;
158 }
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 {
167         struct client_pipe_connection *p;
168
169         for (p = ipc->pipe_connections; p; p = p->next) {
170                 const char *ipc_remote_name;
171
172                 if (!rpc_pipe_np_smb_conn(p->pipe)) {
173                         return NT_STATUS_PIPE_EMPTY;
174                 }
175
176                 ipc_remote_name = smbXcli_conn_remote_name(ipc->cli->conn);
177
178                 if (strequal(ipc_remote_name, p->pipe->desthost)
179                     && ndr_syntax_id_equal(&p->pipe->abstract_syntax,
180                                            &table->syntax_id)) {
181                         *presult = p->pipe;
182                         return NT_STATUS_OK;
183                 }
184         }
185
186         return NT_STATUS_PIPE_NOT_AVAILABLE;
187 }
188
189 /********************************************************************
190 ********************************************************************/
191
192 static NTSTATUS pipe_cm_connect(TALLOC_CTX *mem_ctx,
193                                 struct client_ipc_connection *ipc,
194                                 const struct ndr_interface_table *table,
195                                 struct rpc_pipe_client **presult)
196 {
197         struct client_pipe_connection *p;
198         NTSTATUS status;
199
200         p = talloc_zero_array(mem_ctx, struct client_pipe_connection, 1);
201         if (!p) {
202                 return NT_STATUS_NO_MEMORY;
203         }
204
205         status = cli_rpc_pipe_open_noauth(ipc->cli, table, &p->pipe);
206         if (!NT_STATUS_IS_OK(status)) {
207                 TALLOC_FREE(p);
208                 return status;
209         }
210
211         DLIST_ADD(ipc->pipe_connections, p);
212
213         *presult = p->pipe;
214         return NT_STATUS_OK;
215 }
216
217 /********************************************************************
218 ********************************************************************/
219
220 static NTSTATUS pipe_cm_open(TALLOC_CTX *ctx,
221                              struct client_ipc_connection *ipc,
222                              const struct ndr_interface_table *table,
223                              struct rpc_pipe_client **presult)
224 {
225         if (NT_STATUS_IS_OK(pipe_cm_find(ipc, table, presult))) {
226                 return NT_STATUS_OK;
227         }
228
229         return pipe_cm_connect(ctx, ipc, table, presult);
230 }
231
232 /********************************************************************
233 ********************************************************************/
234
235 WERROR libnetapi_open_pipe(struct libnetapi_ctx *ctx,
236                            const char *server_name,
237                            const struct ndr_interface_table *table,
238                            struct rpc_pipe_client **presult)
239 {
240         struct rpc_pipe_client *result = NULL;
241         NTSTATUS status;
242         WERROR werr;
243         struct client_ipc_connection *ipc = NULL;
244
245         if (!presult) {
246                 return WERR_INVALID_PARAM;
247         }
248
249         werr = libnetapi_open_ipc_connection(ctx, server_name, &ipc);
250         if (!W_ERROR_IS_OK(werr)) {
251                 return werr;
252         }
253
254         status = pipe_cm_open(ctx, ipc, table, &result);
255         if (!NT_STATUS_IS_OK(status)) {
256                 libnetapi_set_error_string(ctx, "failed to open PIPE %s: %s",
257                         table->name,
258                         get_friendly_nt_error_msg(status));
259                 return WERR_DEST_NOT_FOUND;
260         }
261
262         *presult = result;
263
264         return WERR_OK;
265 }
266
267 /********************************************************************
268 ********************************************************************/
269
270 WERROR libnetapi_get_binding_handle(struct libnetapi_ctx *ctx,
271                                     const char *server_name,
272                                     const struct ndr_interface_table *table,
273                                     struct dcerpc_binding_handle **binding_handle)
274 {
275         struct rpc_pipe_client *pipe_cli;
276         WERROR result;
277
278         *binding_handle = NULL;
279
280         result = libnetapi_open_pipe(ctx, server_name, table, &pipe_cli);
281         if (!W_ERROR_IS_OK(result)) {
282                 return result;
283         }
284
285         *binding_handle = pipe_cli->binding_handle;
286
287         return WERR_OK;
288 }