Merge 2610c05b5b95cc7036b3d6dfb894c6cfbdb68483 as Samba-4.0alpha16
[amitay/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 "popt_common.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
28 /********************************************************************
29 ********************************************************************/
30
31 struct client_ipc_connection {
32         struct client_ipc_connection *prev, *next;
33         struct cli_state *cli;
34         struct client_pipe_connection *pipe_connections;
35 };
36
37 struct client_pipe_connection {
38         struct client_pipe_connection *prev, *next;
39         struct rpc_pipe_client *pipe;
40 };
41
42 /********************************************************************
43 ********************************************************************/
44
45 static struct client_ipc_connection *ipc_cm_find(
46         struct libnetapi_private_ctx *priv_ctx, const char *server_name)
47 {
48         struct client_ipc_connection *p;
49
50         for (p = priv_ctx->ipc_connections; p; p = p->next) {
51                 if (strequal(p->cli->desthost, server_name)) {
52                         return p;
53                 }
54         }
55
56         return NULL;
57 }
58
59 /********************************************************************
60 ********************************************************************/
61
62 static WERROR libnetapi_open_ipc_connection(struct libnetapi_ctx *ctx,
63                                             const char *server_name,
64                                             struct client_ipc_connection **pp)
65 {
66         struct libnetapi_private_ctx *priv_ctx;
67         struct user_auth_info *auth_info = NULL;
68         struct cli_state *cli_ipc = NULL;
69         struct client_ipc_connection *p;
70
71         if (!ctx || !pp || !server_name) {
72                 return WERR_INVALID_PARAM;
73         }
74
75         priv_ctx = (struct libnetapi_private_ctx *)ctx->private_data;
76
77         p = ipc_cm_find(priv_ctx, server_name);
78         if (p) {
79                 *pp = p;
80                 return WERR_OK;
81         }
82
83         auth_info = user_auth_info_init(ctx);
84         if (!auth_info) {
85                 return WERR_NOMEM;
86         }
87         auth_info->signing_state = Undefined;
88         set_cmdline_auth_info_use_kerberos(auth_info, ctx->use_kerberos);
89         set_cmdline_auth_info_username(auth_info, ctx->username);
90         if (ctx->password) {
91                 set_cmdline_auth_info_password(auth_info, ctx->password);
92         } else {
93                 set_cmdline_auth_info_getpass(auth_info);
94         }
95
96         if (ctx->username && ctx->username[0] &&
97             ctx->password && ctx->password[0] &&
98             ctx->use_kerberos) {
99                 set_cmdline_auth_info_fallback_after_kerberos(auth_info, true);
100         }
101
102         if (ctx->use_ccache) {
103                 set_cmdline_auth_info_use_ccache(auth_info, true);
104         }
105
106         cli_ipc = cli_cm_open(ctx, NULL,
107                                 server_name, "IPC$",
108                                 auth_info,
109                                 false, false,
110                                 PROTOCOL_NT1,
111                                 0, 0x20);
112         if (cli_ipc) {
113                 cli_set_username(cli_ipc, ctx->username);
114                 cli_set_password(cli_ipc, ctx->password);
115                 cli_set_domain(cli_ipc, ctx->workgroup);
116         }
117         TALLOC_FREE(auth_info);
118
119         if (!cli_ipc) {
120                 libnetapi_set_error_string(ctx,
121                         "Failed to connect to IPC$ share on %s", server_name);
122                 return WERR_CAN_NOT_COMPLETE;
123         }
124
125         p = talloc_zero(ctx, struct client_ipc_connection);
126         if (p == NULL) {
127                 return WERR_NOMEM;
128         }
129
130         p->cli = cli_ipc;
131         DLIST_ADD(priv_ctx->ipc_connections, p);
132
133         *pp = p;
134
135         return WERR_OK;
136 }
137
138 /********************************************************************
139 ********************************************************************/
140
141 WERROR libnetapi_shutdown_cm(struct libnetapi_ctx *ctx)
142 {
143         struct libnetapi_private_ctx *priv_ctx =
144                 (struct libnetapi_private_ctx *)ctx->private_data;
145         struct client_ipc_connection *p;
146
147         for (p = priv_ctx->ipc_connections; p; p = p->next) {
148                 cli_shutdown(p->cli);
149         }
150
151         return WERR_OK;
152 }
153
154 /********************************************************************
155 ********************************************************************/
156
157 static NTSTATUS pipe_cm_find(struct client_ipc_connection *ipc,
158                              const struct ndr_syntax_id *interface,
159                              struct rpc_pipe_client **presult)
160 {
161         struct client_pipe_connection *p;
162
163         for (p = ipc->pipe_connections; p; p = p->next) {
164
165                 if (!rpc_pipe_np_smb_conn(p->pipe)) {
166                         return NT_STATUS_PIPE_EMPTY;
167                 }
168
169                 if (strequal(ipc->cli->desthost, p->pipe->desthost)
170                     && ndr_syntax_id_equal(&p->pipe->abstract_syntax,
171                                            interface)) {
172                         *presult = p->pipe;
173                         return NT_STATUS_OK;
174                 }
175         }
176
177         return NT_STATUS_PIPE_NOT_AVAILABLE;
178 }
179
180 /********************************************************************
181 ********************************************************************/
182
183 static NTSTATUS pipe_cm_connect(TALLOC_CTX *mem_ctx,
184                                 struct client_ipc_connection *ipc,
185                                 const struct ndr_syntax_id *interface,
186                                 struct rpc_pipe_client **presult)
187 {
188         struct client_pipe_connection *p;
189         NTSTATUS status;
190
191         p = talloc_zero_array(mem_ctx, struct client_pipe_connection, 1);
192         if (!p) {
193                 return NT_STATUS_NO_MEMORY;
194         }
195
196         status = cli_rpc_pipe_open_noauth(ipc->cli, interface, &p->pipe);
197         if (!NT_STATUS_IS_OK(status)) {
198                 TALLOC_FREE(p);
199                 return status;
200         }
201
202         DLIST_ADD(ipc->pipe_connections, p);
203
204         *presult = p->pipe;
205         return NT_STATUS_OK;
206 }
207
208 /********************************************************************
209 ********************************************************************/
210
211 static NTSTATUS pipe_cm_open(TALLOC_CTX *ctx,
212                              struct client_ipc_connection *ipc,
213                              const struct ndr_syntax_id *interface,
214                              struct rpc_pipe_client **presult)
215 {
216         if (NT_STATUS_IS_OK(pipe_cm_find(ipc, interface, presult))) {
217                 return NT_STATUS_OK;
218         }
219
220         return pipe_cm_connect(ctx, ipc, interface, presult);
221 }
222
223 /********************************************************************
224 ********************************************************************/
225
226 WERROR libnetapi_open_pipe(struct libnetapi_ctx *ctx,
227                            const char *server_name,
228                            const struct ndr_syntax_id *interface,
229                            struct rpc_pipe_client **presult)
230 {
231         struct rpc_pipe_client *result = NULL;
232         NTSTATUS status;
233         WERROR werr;
234         struct client_ipc_connection *ipc = NULL;
235
236         if (!presult) {
237                 return WERR_INVALID_PARAM;
238         }
239
240         werr = libnetapi_open_ipc_connection(ctx, server_name, &ipc);
241         if (!W_ERROR_IS_OK(werr)) {
242                 return werr;
243         }
244
245         status = pipe_cm_open(ctx, ipc, interface, &result);
246         if (!NT_STATUS_IS_OK(status)) {
247                 libnetapi_set_error_string(ctx, "failed to open PIPE %s: %s",
248                         get_pipe_name_from_syntax(talloc_tos(), interface),
249                         get_friendly_nt_error_msg(status));
250                 return WERR_DEST_NOT_FOUND;
251         }
252
253         *presult = result;
254
255         return WERR_OK;
256 }
257
258 /********************************************************************
259 ********************************************************************/
260
261 WERROR libnetapi_get_binding_handle(struct libnetapi_ctx *ctx,
262                                     const char *server_name,
263                                     const struct ndr_syntax_id *interface,
264                                     struct dcerpc_binding_handle **binding_handle)
265 {
266         struct rpc_pipe_client *pipe_cli;
267         WERROR result;
268
269         *binding_handle = NULL;
270
271         result = libnetapi_open_pipe(ctx, server_name, interface, &pipe_cli);
272         if (!W_ERROR_IS_OK(result)) {
273                 return result;
274         }
275
276         *binding_handle = pipe_cli->binding_handle;
277
278         return WERR_OK;
279 }