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