r12510: Change the DCE/RPC interfaces to take a pointer to a
[samba.git] / source4 / winbind / wb_connect_lsa.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    Connect to the LSA pipe, given an smbcli_tree and possibly some
5    credentials. Try ntlmssp, schannel and anon in that order.
6
7    Copyright (C) Volker Lendecke 2005
8    
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 2 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24 #include "includes.h"
25 #include "libcli/composite/composite.h"
26
27 #include "libcli/raw/libcliraw.h"
28 #include "librpc/gen_ndr/ndr_lsa.h"
29
30 /* Helper to initialize LSA with a specific auth methods. Verify by opening
31  * the LSA policy. */
32
33 struct init_lsa_state {
34         struct composite_context *ctx;
35         struct dcerpc_pipe *lsa_pipe;
36
37         uint8_t auth_type;
38         struct cli_credentials *creds;
39
40         struct lsa_ObjectAttribute objectattr;
41         struct lsa_OpenPolicy2 openpolicy;
42         struct policy_handle *handle;
43 };
44
45 static void init_lsa_recv_pipe(struct composite_context *ctx);
46 static void init_lsa_recv_anon_bind(struct composite_context *ctx);
47 static void init_lsa_recv_auth_bind(struct composite_context *ctx);
48 static void init_lsa_recv_openpol(struct rpc_request *req);
49
50 struct composite_context *wb_init_lsa_send(TALLOC_CTX *mem_ctx,
51                                            struct smbcli_tree *tree,
52                                            uint8_t auth_type,
53                                            struct cli_credentials *creds)
54 {
55         struct composite_context *result, *ctx;
56         struct init_lsa_state *state;
57
58         result = talloc(mem_ctx, struct composite_context);
59         if (result == NULL) goto failed;
60         result->state = COMPOSITE_STATE_IN_PROGRESS;
61         result->async.fn = NULL;
62         result->event_ctx = tree->session->transport->socket->event.ctx;
63
64         state = talloc(result, struct init_lsa_state);
65         if (state == NULL) goto failed;
66         state->ctx = result;
67         result->private_data = state;
68
69         state->auth_type = auth_type;
70         state->creds = creds;
71
72         state->lsa_pipe = dcerpc_pipe_init(state, result->event_ctx);
73         if (state->lsa_pipe == NULL) goto failed;
74
75         ctx = dcerpc_pipe_open_smb_send(state->lsa_pipe->conn, tree,
76                                         "\\lsarpc");
77         ctx->async.fn = init_lsa_recv_pipe;
78         ctx->async.private_data = state;
79         return result;
80         
81  failed:
82         talloc_free(result);
83         return NULL;
84 }
85
86 static void init_lsa_recv_pipe(struct composite_context *ctx)
87 {
88         struct init_lsa_state *state =
89                 talloc_get_type(ctx->async.private_data,
90                                 struct init_lsa_state);
91
92         state->ctx->status = dcerpc_pipe_open_smb_recv(ctx);
93         if (!composite_is_ok(state->ctx)) return;
94
95         switch (state->auth_type) {
96         case DCERPC_AUTH_TYPE_NONE:
97                 ctx = dcerpc_bind_auth_none_send(state, state->lsa_pipe,
98                                                                                  &dcerpc_table_lsarpc);
99                 composite_continue(state->ctx, ctx, init_lsa_recv_anon_bind,
100                                    state);
101                 break;
102         case DCERPC_AUTH_TYPE_NTLMSSP:
103         case DCERPC_AUTH_TYPE_SCHANNEL:
104                 if (state->creds == NULL) {
105                         composite_error(state->ctx, NT_STATUS_INTERNAL_ERROR);
106                         return;
107                 }
108                 state->lsa_pipe->conn->flags |= (DCERPC_SIGN | DCERPC_SEAL);
109                 ctx = dcerpc_bind_auth_send(state, state->lsa_pipe,
110                                                                         &dcerpc_table_lsarpc,
111                                             state->creds, state->auth_type,
112                                             NULL);
113                 composite_continue(state->ctx, ctx, init_lsa_recv_auth_bind,
114                                    state);
115                 break;
116         default:
117                 composite_error(state->ctx, NT_STATUS_INTERNAL_ERROR);
118         }
119 }
120
121 static void init_lsa_recv_anon_bind(struct composite_context *ctx)
122 {
123         struct init_lsa_state *state =
124                 talloc_get_type(ctx->async.private_data,
125                                 struct init_lsa_state);
126         struct rpc_request *req;
127
128         state->ctx->status = dcerpc_bind_auth_none_recv(ctx);
129         if (!composite_is_ok(state->ctx)) return;
130                         
131         state->handle = talloc(state, struct policy_handle);
132         if (composite_nomem(state->handle, state->ctx)) return;
133
134         state->openpolicy.in.system_name =
135                 talloc_asprintf(state, "\\\\%s",
136                                 dcerpc_server_name(state->lsa_pipe));
137         ZERO_STRUCT(state->objectattr);
138         state->openpolicy.in.attr = &state->objectattr;
139         state->openpolicy.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
140         state->openpolicy.out.handle = state->handle;
141
142         req = dcerpc_lsa_OpenPolicy2_send(state->lsa_pipe, state,
143                                           &state->openpolicy);
144         composite_continue_rpc(state->ctx, req, init_lsa_recv_openpol, state);
145 }
146
147 static void init_lsa_recv_auth_bind(struct composite_context *ctx)
148 {
149         struct init_lsa_state *state =
150                 talloc_get_type(ctx->async.private_data,
151                                 struct init_lsa_state);
152         struct rpc_request *req;
153
154         state->ctx->status = dcerpc_bind_auth_recv(ctx);
155         if (!composite_is_ok(state->ctx)) return;
156                         
157         state->handle = talloc(state, struct policy_handle);
158         if (composite_nomem(state->handle, state->ctx)) return;
159
160         state->openpolicy.in.system_name =
161                 talloc_asprintf(state, "\\\\%s",
162                                 dcerpc_server_name(state->lsa_pipe));
163         ZERO_STRUCT(state->objectattr);
164         state->openpolicy.in.attr = &state->objectattr;
165         state->openpolicy.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
166         state->openpolicy.out.handle = state->handle;
167
168         req = dcerpc_lsa_OpenPolicy2_send(state->lsa_pipe, state,
169                                           &state->openpolicy);
170         composite_continue_rpc(state->ctx, req, init_lsa_recv_openpol, state);
171 }
172
173 static void init_lsa_recv_openpol(struct rpc_request *req)
174 {
175         struct init_lsa_state *state =
176                 talloc_get_type(req->async.private,
177                                 struct init_lsa_state);
178
179         state->ctx->status = dcerpc_ndr_request_recv(req);
180         if (!composite_is_ok(state->ctx)) return;
181         state->ctx->status = state->openpolicy.out.result;
182         if (!composite_is_ok(state->ctx)) return;
183
184         composite_done(state->ctx);
185 }
186
187 NTSTATUS wb_init_lsa_recv(struct composite_context *c,
188                           TALLOC_CTX *mem_ctx,
189                           struct dcerpc_pipe **lsa_pipe,
190                           struct policy_handle **lsa_policy)
191 {
192         NTSTATUS status = composite_wait(c);
193         if (NT_STATUS_IS_OK(status)) {
194                 struct init_lsa_state *state =
195                         talloc_get_type(c->private_data,
196                                         struct init_lsa_state);
197                 *lsa_pipe = talloc_steal(mem_ctx, state->lsa_pipe);
198                 *lsa_policy = talloc_steal(mem_ctx, state->handle);
199         }
200         talloc_free(c);
201         return status;
202 }
203
204
205 /*
206  * Connect to LSA using the credentials, try NTLMSSP and SCHANNEL using the
207  * given credentials. If both fail or no credentials are available, fall back
208  * to an anonymous bind.
209  */
210
211 struct connect_lsa_state {
212         struct composite_context *ctx;
213         struct smbcli_tree *tree;
214         struct cli_credentials *credentials;
215
216         uint8_t auth_type;
217         struct dcerpc_pipe *lsa_pipe;
218         struct policy_handle *lsa_policy;
219 };
220
221 static void connect_lsa_recv_ntlmssp(struct composite_context *ctx);
222 static void connect_lsa_recv_schannel(struct composite_context *ctx);
223 static void connect_lsa_recv_anon(struct composite_context *ctx);
224
225 struct composite_context *wb_connect_lsa_send(TALLOC_CTX *mem_ctx,
226                                               struct smbcli_tree *tree,
227                                               struct cli_credentials *credentials)
228 {
229         struct composite_context *result, *ctx;
230         struct connect_lsa_state *state;
231
232         result = talloc(mem_ctx, struct composite_context);
233         if (result == NULL) goto failed;
234         result->state = COMPOSITE_STATE_IN_PROGRESS;
235         result->async.fn = NULL;
236         result->event_ctx = tree->session->transport->socket->event.ctx;
237
238         state = talloc(result, struct connect_lsa_state);
239         if (state == NULL) goto failed;
240         state->ctx = result;
241         result->private_data = state;
242
243         state->tree = tree;
244         state->credentials = credentials;
245
246         if (credentials == NULL) {
247                 ctx = wb_init_lsa_send(state, tree, DCERPC_AUTH_TYPE_NONE,
248                                        NULL);
249                 if (ctx == NULL) goto failed;
250                 ctx->async.fn = connect_lsa_recv_anon;
251                 ctx->async.private_data = state;
252                 return result;
253         }
254
255         ctx = wb_init_lsa_send(state, tree, DCERPC_AUTH_TYPE_NTLMSSP,
256                                credentials);
257         if (ctx == NULL) goto failed;
258         ctx->async.fn = connect_lsa_recv_ntlmssp;
259         ctx->async.private_data = state;
260         return result;
261
262  failed:
263         talloc_free(result);
264         return NULL;
265 }
266
267 static void connect_lsa_recv_ntlmssp(struct composite_context *ctx)
268 {
269         struct connect_lsa_state *state =
270                 talloc_get_type(ctx->async.private_data,
271                                 struct connect_lsa_state);
272
273         state->ctx->status = wb_init_lsa_recv(ctx, state, &state->lsa_pipe,
274                                               &state->lsa_policy);
275
276         if (NT_STATUS_IS_OK(state->ctx->status)) {
277                 state->auth_type = DCERPC_AUTH_TYPE_NTLMSSP;
278                 composite_done(state->ctx);
279                 return;
280         }
281
282         ctx = wb_init_lsa_send(state, state->tree, DCERPC_AUTH_TYPE_SCHANNEL,
283                                state->credentials);
284         composite_continue(state->ctx, ctx,
285                            connect_lsa_recv_schannel, state);
286 }
287
288 static void connect_lsa_recv_schannel(struct composite_context *ctx)
289 {
290         struct connect_lsa_state *state =
291                 talloc_get_type(ctx->async.private_data,
292                                 struct connect_lsa_state);
293
294         state->ctx->status = wb_init_lsa_recv(ctx, state, &state->lsa_pipe,
295                                               &state->lsa_policy);
296
297         if (NT_STATUS_IS_OK(state->ctx->status)) {
298                 state->auth_type = DCERPC_AUTH_TYPE_SCHANNEL;
299                 composite_done(state->ctx);
300                 return;
301         }
302
303         ctx = wb_init_lsa_send(state, state->tree, DCERPC_AUTH_TYPE_NONE,
304                                state->credentials);
305         composite_continue(state->ctx, ctx,
306                            connect_lsa_recv_anon, state);
307 }
308
309 static void connect_lsa_recv_anon(struct composite_context *ctx)
310 {
311         struct connect_lsa_state *state =
312                 talloc_get_type(ctx->async.private_data,
313                                 struct connect_lsa_state);
314
315         state->ctx->status = wb_init_lsa_recv(ctx, state, &state->lsa_pipe,
316                                               &state->lsa_policy);
317         if (!composite_is_ok(state->ctx)) return;
318
319         state->auth_type = DCERPC_AUTH_TYPE_NONE;
320         composite_done(state->ctx);
321 }
322
323 NTSTATUS wb_connect_lsa_recv(struct composite_context *c,
324                              TALLOC_CTX *mem_ctx,
325                              uint8_t *auth_type,
326                              struct dcerpc_pipe **lsa_pipe,
327                              struct policy_handle **lsa_policy)
328 {
329         NTSTATUS status = composite_wait(c);
330         if (NT_STATUS_IS_OK(status)) {
331                 struct connect_lsa_state *state =
332                         talloc_get_type(c->private_data,
333                                         struct connect_lsa_state);
334                 *auth_type = state->auth_type;
335                 *lsa_pipe = talloc_steal(mem_ctx, state->lsa_pipe);
336                 *lsa_policy = talloc_steal(mem_ctx, state->lsa_policy);
337         }
338         talloc_free(c);
339         return status;
340 }
341
342 NTSTATUS wb_connect_lsa(TALLOC_CTX *mem_ctx,
343                         struct smbcli_tree *tree,
344                         struct cli_credentials *credentials,
345                         uint8_t *auth_type,
346                         struct dcerpc_pipe **lsa_pipe,
347                         struct policy_handle **lsa_policy)
348 {
349         struct composite_context *c;
350         c = wb_connect_lsa_send(mem_ctx, tree, credentials);
351         return wb_connect_lsa_recv(c, mem_ctx, auth_type, lsa_pipe,
352                                    lsa_policy);
353 }