r26327: Explicit loadparm_context for RPC client functions.
[gd/samba-autobuild/.git] / source4 / librpc / rpc / dcerpc_auth.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    Generic Authentication Interface
5
6    Copyright (C) Andrew Tridgell 2003
7    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005
8    Copyright (C) Stefan Metzmacher 2004
9    
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 3 of the License, or
13    (at your option) any later version.
14    
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19    
20    You should have received a copy of the GNU General Public License
21    along with this program.  If not, see <http://www.gnu.org/licenses/>.
22 */
23
24 #include "includes.h"
25 #include "libcli/composite/composite.h"
26 #include "auth/gensec/gensec.h"
27 #include "librpc/rpc/dcerpc.h"
28 #include "param/param.h"
29
30 /*
31   return the rpc syntax and transfer syntax given the pipe uuid and version
32 */
33 static NTSTATUS dcerpc_init_syntaxes(const struct ndr_interface_table *table,
34                               struct ndr_syntax_id *syntax,
35                               struct ndr_syntax_id *transfer_syntax)
36 {
37         syntax->uuid = table->syntax_id.uuid;
38         syntax->if_version = table->syntax_id.if_version;
39
40         *transfer_syntax = ndr_transfer_syntax;
41
42         return NT_STATUS_OK;
43 }
44
45
46 /*
47   Send request to do a non-authenticated dcerpc bind
48 */
49 struct composite_context *dcerpc_bind_auth_none_send(TALLOC_CTX *mem_ctx,
50                                                      struct dcerpc_pipe *p,
51                                                      const struct ndr_interface_table *table)
52 {
53         struct ndr_syntax_id syntax;
54         struct ndr_syntax_id transfer_syntax;
55
56         struct composite_context *c;
57
58         c = composite_create(mem_ctx, p->conn->event_ctx);
59         if (c == NULL) return NULL;
60
61         c->status = dcerpc_init_syntaxes(table,
62                                          &syntax, &transfer_syntax);
63         if (!NT_STATUS_IS_OK(c->status)) {
64                 DEBUG(2,("Invalid uuid string in "
65                          "dcerpc_bind_auth_none_send\n"));
66                 composite_error(c, c->status);
67                 return c;
68         }
69
70         /* c was only allocated as a container for a possible error */
71         talloc_free(c);
72
73         return dcerpc_bind_send(p, mem_ctx, &syntax, &transfer_syntax);
74 }
75
76
77 /*
78   Receive result of a non-authenticated dcerpc bind
79 */
80 NTSTATUS dcerpc_bind_auth_none_recv(struct composite_context *ctx)
81 {
82         return dcerpc_bind_recv(ctx);
83 }
84
85
86 /*
87   Perform sync non-authenticated dcerpc bind
88 */
89 NTSTATUS dcerpc_bind_auth_none(struct dcerpc_pipe *p,
90                                const struct ndr_interface_table *table)
91 {
92         struct composite_context *ctx;
93
94         ctx = dcerpc_bind_auth_none_send(p, p, table);
95         return dcerpc_bind_auth_none_recv(ctx);
96 }
97
98
99 struct bind_auth_state {
100         struct dcerpc_pipe *pipe;
101         DATA_BLOB credentials;
102         bool more_processing;   /* Is there anything more to do after the
103                                  * first bind itself received? */
104 };
105
106 static void bind_auth_recv_alter(struct composite_context *creq);
107
108 static void bind_auth_next_step(struct composite_context *c)
109 {
110         struct bind_auth_state *state;
111         struct dcerpc_security *sec;
112         struct composite_context *creq;
113         bool more_processing = false;
114
115         state = talloc_get_type(c->private_data, struct bind_auth_state);
116         sec = &state->pipe->conn->security_state;
117
118         /* The status value here, from GENSEC is vital to the security
119          * of the system.  Even if the other end accepts, if GENSEC
120          * claims 'MORE_PROCESSING_REQUIRED' then you must keep
121          * feeding it blobs, or else the remote host/attacker might
122          * avoid mutal authentication requirements.
123          *
124          * Likewise, you must not feed GENSEC too much (after the OK),
125          * it doesn't like that either
126          */
127
128         c->status = gensec_update(sec->generic_state, state,
129                                   sec->auth_info->credentials,
130                                   &state->credentials);
131
132         if (NT_STATUS_EQUAL(c->status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
133                 more_processing = true;
134                 c->status = NT_STATUS_OK;
135         }
136
137         if (!composite_is_ok(c)) return;
138
139         if (state->credentials.length == 0) {
140                 composite_done(c);
141                 return;
142         }
143
144         sec->auth_info->credentials = state->credentials;
145
146         if (!more_processing) {
147                 /* NO reply expected, so just send it */
148                 c->status = dcerpc_auth3(state->pipe->conn, state);
149                 if (!composite_is_ok(c)) return;
150
151                 composite_done(c);
152                 return;
153         }
154
155         /* We are demanding a reply, so use a request that will get us one */
156
157         creq = dcerpc_alter_context_send(state->pipe, state,
158                                          &state->pipe->syntax,
159                                          &state->pipe->transfer_syntax);
160         if (composite_nomem(creq, c)) return;
161
162         composite_continue(c, creq, bind_auth_recv_alter, c);
163 }
164
165
166 static void bind_auth_recv_alter(struct composite_context *creq)
167 {
168         struct composite_context *c = talloc_get_type(creq->async.private_data,
169                                                       struct composite_context);
170
171         c->status = dcerpc_alter_context_recv(creq);
172         if (!composite_is_ok(c)) return;
173
174         bind_auth_next_step(c);
175 }
176
177
178 static void bind_auth_recv_bindreply(struct composite_context *creq)
179 {
180         struct composite_context *c = talloc_get_type(creq->async.private_data,
181                                                       struct composite_context);
182         struct bind_auth_state *state = talloc_get_type(c->private_data,
183                                                         struct bind_auth_state);
184
185         c->status = dcerpc_bind_recv(creq);
186         if (!composite_is_ok(c)) return;
187
188         if (!state->more_processing) {
189                 /* The first gensec_update has not requested a second run, so
190                  * we're done here. */
191                 composite_done(c);
192                 return;
193         }
194
195         bind_auth_next_step(c);
196 }
197
198
199 /**
200    Bind to a DCE/RPC pipe, send async request
201    @param mem_ctx TALLOC_CTX for the allocation of the composite_context
202    @param p The dcerpc_pipe to bind (must already be connected)
203    @param table The interface table to use (the DCE/RPC bind both selects and interface and authenticates)
204    @param credentials The credentials of the account to connect with 
205    @param auth_type Select the authentication scheme to use
206    @param auth_level Chooses between unprotected (connect), signed or sealed
207    @param service The service (used by Kerberos to select the service principal to contact)
208    @retval A composite context describing the partial state of the bind
209 */
210
211 struct composite_context *dcerpc_bind_auth_send(TALLOC_CTX *mem_ctx,
212                                                 struct dcerpc_pipe *p,
213                                                 const struct ndr_interface_table *table,
214                                                 struct cli_credentials *credentials,
215                                                 struct loadparm_context *lp_ctx,
216                                                 uint8_t auth_type, uint8_t auth_level,
217                                                 const char *service)
218 {
219         struct composite_context *c, *creq;
220         struct bind_auth_state *state;
221         struct dcerpc_security *sec;
222
223         struct ndr_syntax_id syntax, transfer_syntax;
224
225         /* composite context allocation and setup */
226         c = composite_create(mem_ctx, p->conn->event_ctx);
227         if (c == NULL) return NULL;
228
229         state = talloc(c, struct bind_auth_state);
230         if (composite_nomem(state, c)) return c;
231         c->private_data = state;
232
233         state->pipe = p;
234
235         c->status = dcerpc_init_syntaxes(table,
236                                          &syntax,
237                                          &transfer_syntax);
238         if (!composite_is_ok(c)) return c;
239
240         sec = &p->conn->security_state;
241
242         c->status = gensec_client_start(p, &sec->generic_state,
243                                         p->conn->event_ctx,
244                                         lp_ctx);
245         if (!NT_STATUS_IS_OK(c->status)) {
246                 DEBUG(1, ("Failed to start GENSEC client mode: %s\n",
247                           nt_errstr(c->status)));
248                 composite_error(c, c->status);
249                 return c;
250         }
251
252         c->status = gensec_set_credentials(sec->generic_state, credentials);
253         if (!NT_STATUS_IS_OK(c->status)) {
254                 DEBUG(1, ("Failed to set GENSEC client credentials: %s\n",
255                           nt_errstr(c->status)));
256                 composite_error(c, c->status);
257                 return c;
258         }
259
260         c->status = gensec_set_target_hostname(sec->generic_state,
261                                                p->conn->transport.target_hostname(p->conn));
262         if (!NT_STATUS_IS_OK(c->status)) {
263                 DEBUG(1, ("Failed to set GENSEC target hostname: %s\n", 
264                           nt_errstr(c->status)));
265                 composite_error(c, c->status);
266                 return c;
267         }
268
269         if (service != NULL) {
270                 c->status = gensec_set_target_service(sec->generic_state,
271                                                       service);
272                 if (!NT_STATUS_IS_OK(c->status)) {
273                         DEBUG(1, ("Failed to set GENSEC target service: %s\n",
274                                   nt_errstr(c->status)));
275                         composite_error(c, c->status);
276                         return c;
277                 }
278         }
279
280         c->status = gensec_start_mech_by_authtype(sec->generic_state,
281                                                   auth_type, auth_level);
282         if (!NT_STATUS_IS_OK(c->status)) {
283                 DEBUG(1, ("Failed to start GENSEC client mechanism %s: %s\n",
284                           gensec_get_name_by_authtype(auth_type),
285                           nt_errstr(c->status)));
286                 composite_error(c, c->status);
287                 return c;
288         }
289
290         sec->auth_info = talloc(p, struct dcerpc_auth);
291         if (composite_nomem(sec->auth_info, c)) return c;
292
293         sec->auth_info->auth_type = auth_type;
294         sec->auth_info->auth_level = auth_level,
295         sec->auth_info->auth_pad_length = 0;
296         sec->auth_info->auth_reserved = 0;
297         sec->auth_info->auth_context_id = random();
298         sec->auth_info->credentials = data_blob(NULL, 0);
299
300         /* The status value here, from GENSEC is vital to the security
301          * of the system.  Even if the other end accepts, if GENSEC
302          * claims 'MORE_PROCESSING_REQUIRED' then you must keep
303          * feeding it blobs, or else the remote host/attacker might
304          * avoid mutal authentication requirements.
305          *
306          * Likewise, you must not feed GENSEC too much (after the OK),
307          * it doesn't like that either
308          */
309
310         c->status = gensec_update(sec->generic_state, state,
311                                   sec->auth_info->credentials,
312                                   &state->credentials);
313         if (!NT_STATUS_IS_OK(c->status) &&
314             !NT_STATUS_EQUAL(c->status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
315                 composite_error(c, c->status);
316                 return c;
317         }
318
319         state->more_processing = NT_STATUS_EQUAL(c->status,
320                                                  NT_STATUS_MORE_PROCESSING_REQUIRED);
321
322         if (state->credentials.length == 0) {
323                 composite_done(c);
324                 return c;
325         }
326
327         sec->auth_info->credentials = state->credentials;
328
329         /* The first request always is a dcerpc_bind. The subsequent ones
330          * depend on gensec results */
331         creq = dcerpc_bind_send(p, state, &syntax, &transfer_syntax);
332         if (composite_nomem(creq, c)) return c;
333
334         composite_continue(c, creq, bind_auth_recv_bindreply, c);
335         return c;
336 }
337
338
339 /**
340    Bind to a DCE/RPC pipe, receive result
341    @param creq A composite context describing state of async call
342    @retval NTSTATUS code
343 */
344
345 NTSTATUS dcerpc_bind_auth_recv(struct composite_context *creq)
346 {
347         NTSTATUS result = composite_wait(creq);
348         struct bind_auth_state *state = talloc_get_type(creq->private_data,
349                                                         struct bind_auth_state);
350
351         if (NT_STATUS_IS_OK(result)) {
352                 /*
353                   after a successful authenticated bind the session
354                   key reverts to the generic session key
355                 */
356                 state->pipe->conn->security_state.session_key = dcerpc_generic_session_key;
357         }
358         
359         talloc_free(creq);
360         return result;
361 }
362
363
364 /**
365    Perform a GENSEC authenticated bind to a DCE/RPC pipe, sync
366    @param p The dcerpc_pipe to bind (must already be connected)
367    @param table The interface table to use (the DCE/RPC bind both selects and interface and authenticates)
368    @param credentials The credentials of the account to connect with 
369    @param auth_type Select the authentication scheme to use
370    @param auth_level Chooses between unprotected (connect), signed or sealed
371    @param service The service (used by Kerberos to select the service principal to contact)
372    @retval NTSTATUS status code
373 */
374
375 NTSTATUS dcerpc_bind_auth(struct dcerpc_pipe *p,
376                           const struct ndr_interface_table *table,
377                           struct cli_credentials *credentials,
378                           struct loadparm_context *lp_ctx,
379                           uint8_t auth_type, uint8_t auth_level,
380                           const char *service)
381 {
382         struct composite_context *creq;
383         creq = dcerpc_bind_auth_send(p, p, table, credentials, lp_ctx,
384                                      auth_type, auth_level, service);
385         return dcerpc_bind_auth_recv(creq);
386 }