22d874cbf3e4bb0b4f5b227250170aca6e406799
[abartlet/samba.git/.git] / source4 / librpc / rpc / dcerpc_util.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    dcerpc utility functions
5
6    Copyright (C) Andrew Tridgell 2003
7    Copyright (C) Jelmer Vernooij 2004
8    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
9    Copyright (C) Rafal Szczesniak 2006
10    
11    This program is free software; you can redistribute it and/or modify
12    it under the terms of the GNU General Public License as published by
13    the Free Software Foundation; either version 3 of the License, or
14    (at your option) any later version.
15    
16    This program is distributed in the hope that it will be useful,
17    but WITHOUT ANY WARRANTY; without even the implied warranty of
18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19    GNU General Public License for more details.
20    
21    You should have received a copy of the GNU General Public License
22    along with this program.  If not, see <http://www.gnu.org/licenses/>.
23 */
24
25 #include "includes.h"
26 #include "lib/events/events.h"
27 #include "libcli/composite/composite.h"
28 #include "librpc/gen_ndr/ndr_epmapper_c.h"
29 #include "librpc/gen_ndr/ndr_dcerpc.h"
30 #include "librpc/gen_ndr/ndr_misc.h"
31 #include "librpc/rpc/dcerpc_proto.h"
32 #include "auth/credentials/credentials.h"
33 #include "param/param.h"
34
35 /*
36   find a dcerpc call on an interface by name
37 */
38 const struct ndr_interface_call *dcerpc_iface_find_call(const struct ndr_interface_table *iface,
39                                                         const char *name)
40 {
41         int i;
42         for (i=0;i<iface->num_calls;i++) {
43                 if (strcmp(iface->calls[i].name, name) == 0) {
44                         return &iface->calls[i];
45                 }
46         }
47         return NULL;
48 }
49
50 /* 
51    push a ncacn_packet into a blob, potentially with auth info
52 */
53 NTSTATUS ncacn_push_auth(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, 
54                          struct smb_iconv_convenience *iconv_convenience,
55                          struct ncacn_packet *pkt,
56                          struct dcerpc_auth *auth_info)
57 {
58         struct ndr_push *ndr;
59         enum ndr_err_code ndr_err;
60
61         ndr = ndr_push_init_ctx(mem_ctx, iconv_convenience);
62         if (!ndr) {
63                 return NT_STATUS_NO_MEMORY;
64         }
65
66         if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
67                 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
68         }
69
70         if (pkt->pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
71                 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
72         }
73
74         if (auth_info) {
75                 pkt->auth_length = auth_info->credentials.length;
76         } else {
77                 pkt->auth_length = 0;
78         }
79
80         ndr_err = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
81         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
82                 return ndr_map_error2ntstatus(ndr_err);
83         }
84
85         if (auth_info) {
86 #if 1
87                 /* With the fix for bug #7146 S3 servers
88                    now cope with this. JRA. */
89                 uint32_t offset = ndr->offset;
90                 ndr_err = ndr_push_align(ndr, 16);
91                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
92                         return ndr_map_error2ntstatus(ndr_err);
93                 }
94                 auth_info->auth_pad_length = ndr->offset - offset;
95 #else
96                 /* Older s3 rpc servers doesn't handle auth padding in
97                    bind requests. Use zero auth padding to keep us
98                    working with old servers */
99                 auth_info->auth_pad_length = 0;
100 #endif
101                 ndr_err = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, auth_info);
102                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
103                         return ndr_map_error2ntstatus(ndr_err);
104                 }
105         }
106
107         *blob = ndr_push_blob(ndr);
108
109         /* fill in the frag length */
110         dcerpc_set_frag_length(blob, blob->length);
111
112         return NT_STATUS_OK;
113 }
114
115
116 struct epm_map_binding_state {
117         struct dcerpc_binding *binding;
118         const struct ndr_interface_table *table;
119         struct dcerpc_pipe *pipe;
120         struct policy_handle handle;
121         struct GUID guid;
122         struct epm_twr_t twr;
123         struct epm_twr_t *twr_r;
124         struct epm_Map r;
125 };
126
127
128 static void continue_epm_recv_binding(struct composite_context *ctx);
129 static void continue_epm_map(struct rpc_request *req);
130
131
132 /*
133   Stage 2 of epm_map_binding: Receive connected rpc pipe and send endpoint
134   mapping rpc request
135 */
136 static void continue_epm_recv_binding(struct composite_context *ctx)
137 {
138         struct rpc_request *map_req;
139
140         struct composite_context *c = talloc_get_type(ctx->async.private_data,
141                                                       struct composite_context);
142         struct epm_map_binding_state *s = talloc_get_type(c->private_data,
143                                                           struct epm_map_binding_state);
144
145         /* receive result of rpc pipe connect request */
146         c->status = dcerpc_pipe_connect_b_recv(ctx, c, &s->pipe);
147         if (!composite_is_ok(c)) return;
148
149         s->pipe->conn->flags |= DCERPC_NDR_REF_ALLOC;
150
151         /* prepare requested binding parameters */
152         s->binding->object         = s->table->syntax_id;
153
154         c->status = dcerpc_binding_build_tower(s->pipe, s->binding, &s->twr.tower);
155         if (!composite_is_ok(c)) return;
156         
157         /* with some nice pretty paper around it of course */
158         s->r.in.object        = &s->guid;
159         s->r.in.map_tower     = &s->twr;
160         s->r.in.entry_handle  = &s->handle;
161         s->r.in.max_towers    = 1;
162         s->r.out.entry_handle = &s->handle;
163
164         /* send request for an endpoint mapping - a rpc request on connected pipe */
165         map_req = dcerpc_epm_Map_send(s->pipe, c, &s->r);
166         if (composite_nomem(map_req, c)) return;
167         
168         composite_continue_rpc(c, map_req, continue_epm_map, c);
169 }
170
171
172 /*
173   Stage 3 of epm_map_binding: Receive endpoint mapping and provide binding details
174 */
175 static void continue_epm_map(struct rpc_request *req)
176 {
177         struct composite_context *c = talloc_get_type(req->async.private_data,
178                                                       struct composite_context);
179         struct epm_map_binding_state *s = talloc_get_type(c->private_data,
180                                                           struct epm_map_binding_state);
181
182         /* receive result of a rpc request */
183         c->status = dcerpc_ndr_request_recv(req);
184         if (!composite_is_ok(c)) return;
185
186         /* check the details */
187         if (s->r.out.result != 0 || *s->r.out.num_towers != 1) {
188                 composite_error(c, NT_STATUS_PORT_UNREACHABLE);
189                 return;
190         }
191         
192         s->twr_r = s->r.out.towers[0].twr;
193         if (s->twr_r == NULL) {
194                 composite_error(c, NT_STATUS_PORT_UNREACHABLE);
195                 return;
196         }
197
198         if (s->twr_r->tower.num_floors != s->twr.tower.num_floors ||
199             s->twr_r->tower.floors[3].lhs.protocol != s->twr.tower.floors[3].lhs.protocol) {
200                 composite_error(c, NT_STATUS_PORT_UNREACHABLE);
201                 return;
202         }
203
204         /* get received endpoint */
205         s->binding->endpoint = talloc_reference(s->binding,
206                                                 dcerpc_floor_get_rhs_data(c, &s->twr_r->tower.floors[3]));
207         if (composite_nomem(s->binding->endpoint, c)) return;
208
209         composite_done(c);
210 }
211
212
213 /*
214   Request for endpoint mapping of dcerpc binding - try to request for endpoint
215   unless there is default one.
216 */
217 struct composite_context *dcerpc_epm_map_binding_send(TALLOC_CTX *mem_ctx,
218                                                       struct dcerpc_binding *binding,
219                                                       const struct ndr_interface_table *table,
220                                                       struct tevent_context *ev,
221                                                       struct loadparm_context *lp_ctx)
222 {
223         struct composite_context *c;
224         struct epm_map_binding_state *s;
225         struct composite_context *pipe_connect_req;
226         struct cli_credentials *anon_creds;
227
228         NTSTATUS status;
229         struct dcerpc_binding *epmapper_binding;
230         int i;
231
232         if (ev == NULL) {
233                 return NULL;
234         }
235
236         /* composite context allocation and setup */
237         c = composite_create(mem_ctx, ev);
238         if (c == NULL) {
239                 return NULL;
240         }
241
242         s = talloc_zero(c, struct epm_map_binding_state);
243         if (composite_nomem(s, c)) return c;
244         c->private_data = s;
245
246         s->binding = binding;
247         s->table   = table;
248
249         /* anonymous credentials for rpc connection used to get endpoint mapping */
250         anon_creds = cli_credentials_init(mem_ctx);
251         cli_credentials_set_anonymous(anon_creds);
252
253         /*
254           First, check if there is a default endpoint specified in the IDL
255         */
256         if (table != NULL) {
257                 struct dcerpc_binding *default_binding;
258
259                 /* Find one of the default pipes for this interface */
260                 for (i = 0; i < table->endpoints->count; i++) {
261                         status = dcerpc_parse_binding(mem_ctx, table->endpoints->names[i], &default_binding);
262
263                         if (NT_STATUS_IS_OK(status)) {
264                                 if (binding->transport == NCA_UNKNOWN) 
265                                         binding->transport = default_binding->transport;
266                                 if (default_binding->transport == binding->transport && 
267                                         default_binding->endpoint) {
268                                         binding->endpoint = talloc_reference(binding, default_binding->endpoint);
269                                         talloc_free(default_binding);
270
271                                         composite_done(c);
272                                         return c;
273
274                                 } else {
275                                         talloc_free(default_binding);
276                                 }
277                         }
278                 }
279         }
280
281         epmapper_binding = talloc_zero(c, struct dcerpc_binding);
282         if (composite_nomem(epmapper_binding, c)) return c;
283
284         /* basic endpoint mapping data */
285         epmapper_binding->transport             = binding->transport;
286         epmapper_binding->host                  = talloc_reference(epmapper_binding, binding->host);
287         epmapper_binding->target_hostname       = epmapper_binding->host;
288         epmapper_binding->options               = NULL;
289         epmapper_binding->flags                 = 0;
290         epmapper_binding->assoc_group_id        = 0;
291         epmapper_binding->endpoint              = NULL;
292
293         /* initiate rpc pipe connection */
294         pipe_connect_req = dcerpc_pipe_connect_b_send(c, epmapper_binding, 
295                                                       &ndr_table_epmapper,
296                                                       anon_creds, c->event_ctx,
297                                                       lp_ctx);
298         if (composite_nomem(pipe_connect_req, c)) return c;
299         
300         composite_continue(c, pipe_connect_req, continue_epm_recv_binding, c);
301         return c;
302 }
303
304
305 /*
306   Receive result of endpoint mapping request
307  */
308 NTSTATUS dcerpc_epm_map_binding_recv(struct composite_context *c)
309 {
310         NTSTATUS status = composite_wait(c);
311         
312         talloc_free(c);
313         return status;
314 }
315
316
317 /*
318   Get endpoint mapping for rpc connection
319 */
320 _PUBLIC_ NTSTATUS dcerpc_epm_map_binding(TALLOC_CTX *mem_ctx, struct dcerpc_binding *binding,
321                                 const struct ndr_interface_table *table, struct tevent_context *ev,
322                                 struct loadparm_context *lp_ctx)
323 {
324         struct composite_context *c;
325
326         c = dcerpc_epm_map_binding_send(mem_ctx, binding, table, ev, lp_ctx);
327         return dcerpc_epm_map_binding_recv(c);
328 }
329
330
331 struct pipe_auth_state {
332         struct dcerpc_pipe *pipe;
333         struct dcerpc_binding *binding;
334         const struct ndr_interface_table *table;
335         struct loadparm_context *lp_ctx;
336         struct cli_credentials *credentials;
337 };
338
339
340 static void continue_auth_schannel(struct composite_context *ctx);
341 static void continue_auth(struct composite_context *ctx);
342 static void continue_auth_none(struct composite_context *ctx);
343 static void continue_ntlmssp_connection(struct composite_context *ctx);
344 static void continue_spnego_after_wrong_pass(struct composite_context *ctx);
345
346
347 /*
348   Stage 2 of pipe_auth: Receive result of schannel bind request
349 */
350 static void continue_auth_schannel(struct composite_context *ctx)
351 {
352         struct composite_context *c = talloc_get_type(ctx->async.private_data,
353                                                       struct composite_context);
354
355         c->status = dcerpc_bind_auth_schannel_recv(ctx);
356         if (!composite_is_ok(c)) return;
357
358         composite_done(c);
359 }
360
361
362 /*
363   Stage 2 of pipe_auth: Receive result of authenticated bind request
364 */
365 static void continue_auth(struct composite_context *ctx)
366 {
367         struct composite_context *c = talloc_get_type(ctx->async.private_data,
368                                                       struct composite_context);
369
370         c->status = dcerpc_bind_auth_recv(ctx);
371         if (!composite_is_ok(c)) return;
372         
373         composite_done(c);
374 }
375 /*
376   Stage 2 of pipe_auth: Receive result of authenticated bind request, but handle fallbacks:
377   SPNEGO -> NTLMSSP
378 */
379 static void continue_auth_auto(struct composite_context *ctx)
380 {
381         struct composite_context *c = talloc_get_type(ctx->async.private_data,
382                                                       struct composite_context);
383         struct pipe_auth_state *s = talloc_get_type(c->private_data, struct pipe_auth_state);
384         struct composite_context *sec_conn_req;
385
386         c->status = dcerpc_bind_auth_recv(ctx);
387         if (NT_STATUS_EQUAL(c->status, NT_STATUS_INVALID_PARAMETER)) {
388                 /*
389                  * Retry with NTLMSSP auth as fallback
390                  * send a request for secondary rpc connection
391                  */
392                 sec_conn_req = dcerpc_secondary_connection_send(s->pipe,
393                                                                 s->binding);
394                 composite_continue(c, sec_conn_req, continue_ntlmssp_connection, c);
395                 return;
396         } else if (NT_STATUS_EQUAL(c->status, NT_STATUS_LOGON_FAILURE)) {
397                 if (cli_credentials_wrong_password(s->credentials)) {
398                         /*
399                          * Retry SPNEGO with a better password
400                          * send a request for secondary rpc connection
401                          */
402                         sec_conn_req = dcerpc_secondary_connection_send(s->pipe,
403                                                                         s->binding);
404                         composite_continue(c, sec_conn_req, continue_spnego_after_wrong_pass, c);
405                         return;
406                 }
407         }
408
409         if (!composite_is_ok(c)) return;
410
411         composite_done(c);
412 }
413
414 /*
415   Stage 3 of pipe_auth (fallback to NTLMSSP case): Receive secondary
416   rpc connection (the first one can't be used any more, due to the
417   bind nak) and perform authenticated bind request
418 */
419 static void continue_ntlmssp_connection(struct composite_context *ctx)
420 {
421         struct composite_context *c;
422         struct pipe_auth_state *s;
423         struct composite_context *auth_req;
424         struct dcerpc_pipe *p2;
425
426         c = talloc_get_type(ctx->async.private_data, struct composite_context);
427         s = talloc_get_type(c->private_data, struct pipe_auth_state);
428
429         /* receive secondary rpc connection */
430         c->status = dcerpc_secondary_connection_recv(ctx, &p2);
431         if (!composite_is_ok(c)) return;
432
433         talloc_steal(s, p2);
434         talloc_steal(p2, s->pipe);
435         s->pipe = p2;
436
437         /* initiate a authenticated bind */
438         auth_req = dcerpc_bind_auth_send(c, s->pipe, s->table,
439                                          s->credentials, 
440                                          lp_gensec_settings(c, s->lp_ctx),
441                                          DCERPC_AUTH_TYPE_NTLMSSP,
442                                          dcerpc_auth_level(s->pipe->conn),
443                                          s->table->authservices->names[0]);
444         composite_continue(c, auth_req, continue_auth, c);
445 }
446
447 /*
448   Stage 3 of pipe_auth (retry on wrong password): Receive secondary
449   rpc connection (the first one can't be used any more, due to the
450   bind nak) and perform authenticated bind request
451 */
452 static void continue_spnego_after_wrong_pass(struct composite_context *ctx)
453 {
454         struct composite_context *c;
455         struct pipe_auth_state *s;
456         struct composite_context *auth_req;
457         struct dcerpc_pipe *p2;
458
459         c = talloc_get_type(ctx->async.private_data, struct composite_context);
460         s = talloc_get_type(c->private_data, struct pipe_auth_state);
461
462         /* receive secondary rpc connection */
463         c->status = dcerpc_secondary_connection_recv(ctx, &p2);
464         if (!composite_is_ok(c)) return;
465
466         talloc_steal(s, p2);
467         talloc_steal(p2, s->pipe);
468         s->pipe = p2;
469
470         /* initiate a authenticated bind */
471         auth_req = dcerpc_bind_auth_send(c, s->pipe, s->table,
472                                          s->credentials, 
473                                          lp_gensec_settings(c, s->lp_ctx), 
474                                          DCERPC_AUTH_TYPE_SPNEGO,
475                                          dcerpc_auth_level(s->pipe->conn),
476                                          s->table->authservices->names[0]);
477         composite_continue(c, auth_req, continue_auth, c);
478 }
479
480
481 /*
482   Stage 2 of pipe_auth: Receive result of non-authenticated bind request
483 */
484 static void continue_auth_none(struct composite_context *ctx)
485 {
486         struct composite_context *c = talloc_get_type(ctx->async.private_data,
487                                                       struct composite_context);
488
489         c->status = dcerpc_bind_auth_none_recv(ctx);
490         if (!composite_is_ok(c)) return;
491         
492         composite_done(c);
493 }
494
495
496 /*
497   Request to perform an authenticated bind if required. Authentication
498   is determined using credentials passed and binding flags.
499 */
500 struct composite_context *dcerpc_pipe_auth_send(struct dcerpc_pipe *p, 
501                                                 struct dcerpc_binding *binding,
502                                                 const struct ndr_interface_table *table,
503                                                 struct cli_credentials *credentials,
504                                                 struct loadparm_context *lp_ctx)
505 {
506         struct composite_context *c;
507         struct pipe_auth_state *s;
508         struct composite_context *auth_schannel_req;
509         struct composite_context *auth_req;
510         struct composite_context *auth_none_req;
511         struct dcerpc_connection *conn;
512         uint8_t auth_type;
513
514         /* composite context allocation and setup */
515         c = composite_create(p, p->conn->event_ctx);
516         if (c == NULL) return NULL;
517
518         s = talloc_zero(c, struct pipe_auth_state);
519         if (composite_nomem(s, c)) return c;
520         c->private_data = s;
521
522         /* store parameters in state structure */
523         s->binding      = binding;
524         s->table        = table;
525         s->credentials  = credentials;
526         s->pipe         = p;
527         s->lp_ctx       = lp_ctx;
528
529         conn = s->pipe->conn;
530         conn->flags = binding->flags;
531
532         if (DEBUGLVL(100)) {
533                 conn->flags |= DCERPC_DEBUG_PRINT_BOTH;
534         }
535         
536         /* remember the binding string for possible secondary connections */
537         conn->binding_string = dcerpc_binding_string(p, binding);
538
539         if (cli_credentials_is_anonymous(s->credentials)) {
540                 auth_none_req = dcerpc_bind_auth_none_send(c, s->pipe, s->table);
541                 composite_continue(c, auth_none_req, continue_auth_none, c);
542                 return c;
543         }
544
545         if ((binding->flags & DCERPC_SCHANNEL) &&
546             !cli_credentials_get_netlogon_creds(s->credentials)) {
547                 /* If we don't already have netlogon credentials for
548                  * the schannel bind, then we have to get these
549                  * first */
550                 auth_schannel_req = dcerpc_bind_auth_schannel_send(c, s->pipe, s->table,
551                                                                    s->credentials, s->lp_ctx,
552                                                                    dcerpc_auth_level(conn));
553                 composite_continue(c, auth_schannel_req, continue_auth_schannel, c);
554                 return c;
555         }
556
557         /*
558          * we rely on the already authenticated CIFS connection
559          * if not doing sign or seal
560          */
561         if (conn->transport.transport == NCACN_NP &&
562             !(s->binding->flags & (DCERPC_SIGN|DCERPC_SEAL))) {
563                 auth_none_req = dcerpc_bind_auth_none_send(c, s->pipe, s->table);
564                 composite_continue(c, auth_none_req, continue_auth_none, c);
565                 return c;
566         }
567
568
569         /* Perform an authenticated DCE-RPC bind
570          */
571         if (!(conn->flags & (DCERPC_SIGN|DCERPC_SEAL))) {
572                 /*
573                   we are doing an authenticated connection,
574                   but not using sign or seal. We must force
575                   the CONNECT dcerpc auth type as a NONE auth
576                   type doesn't allow authentication
577                   information to be passed.
578                 */
579                 conn->flags |= DCERPC_CONNECT;
580         }
581
582         if (s->binding->flags & DCERPC_AUTH_SPNEGO) {
583                 auth_type = DCERPC_AUTH_TYPE_SPNEGO;
584
585         } else if (s->binding->flags & DCERPC_AUTH_KRB5) {
586                 auth_type = DCERPC_AUTH_TYPE_KRB5;
587
588         } else if (s->binding->flags & DCERPC_SCHANNEL) {
589                 auth_type = DCERPC_AUTH_TYPE_SCHANNEL;
590
591         } else if (s->binding->flags & DCERPC_AUTH_NTLM) {
592                 auth_type = DCERPC_AUTH_TYPE_NTLMSSP;
593
594         } else {
595                 /* try SPNEGO with fallback to NTLMSSP */
596                 auth_req = dcerpc_bind_auth_send(c, s->pipe, s->table,
597                                                  s->credentials, 
598                                                  lp_gensec_settings(c, s->lp_ctx), 
599                                                  DCERPC_AUTH_TYPE_SPNEGO,
600                                                  dcerpc_auth_level(conn),
601                                                  s->table->authservices->names[0]);
602                 composite_continue(c, auth_req, continue_auth_auto, c);
603                 return c;
604         }
605
606         auth_req = dcerpc_bind_auth_send(c, s->pipe, s->table,
607                                          s->credentials, 
608                                          lp_gensec_settings(c, s->lp_ctx), 
609                                          auth_type,
610                                          dcerpc_auth_level(conn),
611                                          s->table->authservices->names[0]);
612         composite_continue(c, auth_req, continue_auth, c);
613         return c;
614 }
615
616
617 /*
618   Receive result of authenticated bind request on dcerpc pipe
619
620   This returns *p, which may be different to the one originally
621   supllied, as it rebinds to a new pipe due to authentication fallback
622
623 */
624 NTSTATUS dcerpc_pipe_auth_recv(struct composite_context *c, TALLOC_CTX *mem_ctx, 
625                                struct dcerpc_pipe **p)
626 {
627         NTSTATUS status;
628
629         struct pipe_auth_state *s = talloc_get_type(c->private_data,
630                                                     struct pipe_auth_state);
631         status = composite_wait(c);
632         if (!NT_STATUS_IS_OK(status)) {
633                 char *uuid_str = GUID_string(s->pipe, &s->table->syntax_id.uuid);
634                 DEBUG(0, ("Failed to bind to uuid %s - %s\n", uuid_str, nt_errstr(status)));
635                 talloc_free(uuid_str);
636         } else {
637                 talloc_steal(mem_ctx, s->pipe);
638                 *p = s->pipe;
639         }
640
641         talloc_free(c);
642         return status;
643 }
644
645
646 /* 
647    Perform an authenticated bind if needed - sync version
648
649    This may change *p, as it rebinds to a new pipe due to authentication fallback
650 */
651 _PUBLIC_ NTSTATUS dcerpc_pipe_auth(TALLOC_CTX *mem_ctx,
652                           struct dcerpc_pipe **p, 
653                           struct dcerpc_binding *binding,
654                           const struct ndr_interface_table *table,
655                           struct cli_credentials *credentials,
656                           struct loadparm_context *lp_ctx)
657 {
658         struct composite_context *c;
659
660         c = dcerpc_pipe_auth_send(*p, binding, table, credentials, lp_ctx);
661         return dcerpc_pipe_auth_recv(c, mem_ctx, p);
662 }
663
664
665 NTSTATUS dcerpc_generic_session_key(struct dcerpc_connection *c,
666                                     DATA_BLOB *session_key)
667 {
668         /* this took quite a few CPU cycles to find ... */
669         session_key->data = discard_const_p(unsigned char, "SystemLibraryDTC");
670         session_key->length = 16;
671         return NT_STATUS_OK;
672 }
673
674 /*
675   fetch the user session key - may be default (above) or the SMB session key
676
677   The key is always truncated to 16 bytes 
678 */
679 _PUBLIC_ NTSTATUS dcerpc_fetch_session_key(struct dcerpc_pipe *p,
680                                            DATA_BLOB *session_key)
681 {
682         NTSTATUS status;
683         status = p->conn->security_state.session_key(p->conn, session_key);
684         if (!NT_STATUS_IS_OK(status)) {
685                 return status;
686         }
687
688         session_key->length = MIN(session_key->length, 16);
689
690         return NT_STATUS_OK;
691 }
692
693
694 /*
695   log a rpc packet in a format suitable for ndrdump. This is especially useful
696   for sealed packets, where ethereal cannot easily see the contents
697
698   this triggers on a debug level of >= 10
699 */
700 _PUBLIC_ void dcerpc_log_packet(const char *lockdir,
701                                                                 const struct ndr_interface_table *ndr,
702                        uint32_t opnum, uint32_t flags, 
703                        DATA_BLOB *pkt)
704 {
705         const int num_examples = 20;
706         int i;
707
708         if (lockdir == NULL) return;
709
710         for (i=0;i<num_examples;i++) {
711                 char *name=NULL;
712                 asprintf(&name, "%s/rpclog/%s-%u.%d.%s", 
713                          lockdir, ndr->name, opnum, i,
714                          (flags&NDR_IN)?"in":"out");
715                 if (name == NULL) {
716                         return;
717                 }
718                 if (!file_exist(name)) {
719                         if (file_save(name, pkt->data, pkt->length)) {
720                                 DEBUG(10,("Logged rpc packet to %s\n", name));
721                         }
722                         free(name);
723                         break;
724                 }
725                 free(name);
726         }
727 }
728
729
730
731 /*
732   create a secondary context from a primary connection
733
734   this uses dcerpc_alter_context() to create a new dcerpc context_id
735 */
736 _PUBLIC_ NTSTATUS dcerpc_secondary_context(struct dcerpc_pipe *p, 
737                                   struct dcerpc_pipe **pp2,
738                                   const struct ndr_interface_table *table)
739 {
740         NTSTATUS status;
741         struct dcerpc_pipe *p2;
742         
743         p2 = talloc_zero(p, struct dcerpc_pipe);
744         if (p2 == NULL) {
745                 return NT_STATUS_NO_MEMORY;
746         }
747         p2->conn = talloc_reference(p2, p->conn);
748         p2->request_timeout = p->request_timeout;
749
750         p2->context_id = ++p->conn->next_context_id;
751
752         p2->syntax = table->syntax_id;
753
754         p2->transfer_syntax = p->transfer_syntax;
755
756         p2->binding = talloc_reference(p2, p->binding);
757
758         status = dcerpc_alter_context(p2, p2, &p2->syntax, &p2->transfer_syntax);
759         if (!NT_STATUS_IS_OK(status)) {
760                 talloc_free(p2);
761                 return status;
762         }
763
764         *pp2 = p2;
765
766         return NT_STATUS_OK;
767 }
768
769
770 /*
771   pull an dcerpc_auth structure, taking account of any auth padding in
772   the blob at the end of the structure
773  */
774 NTSTATUS dcerpc_pull_auth_trailer(struct ncacn_packet *pkt,
775                                   TALLOC_CTX *mem_ctx,
776                                   DATA_BLOB *pkt_auth_blob,
777                                   struct dcerpc_auth *auth,
778                                   uint32_t *auth_length,
779                                   bool check_pad)
780 {
781         struct ndr_pull *ndr;
782         enum ndr_err_code ndr_err;
783         uint32_t pad;
784
785         pad = pkt_auth_blob->length - (DCERPC_AUTH_TRAILER_LENGTH + pkt->auth_length);
786
787         /* paranoia check for pad size. This would be caught anyway by
788            the ndr_pull_advance() a few lines down, but it scared
789            Jeremy enough for him to call me, so we might as well check
790            it now, just to prevent someone posting a bogus YouTube
791            video in the future.
792         */
793         if (pad > pkt_auth_blob->length) {
794                 return NT_STATUS_INFO_LENGTH_MISMATCH;
795         }
796
797         *auth_length = pkt_auth_blob->length - pad;
798
799         ndr = ndr_pull_init_blob(pkt_auth_blob, mem_ctx, NULL);
800         if (!ndr) {
801                 return NT_STATUS_NO_MEMORY;
802         }
803
804         if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
805                 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
806         }
807
808         ndr_err = ndr_pull_advance(ndr, pad);
809         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
810                 talloc_free(ndr);
811                 return ndr_map_error2ntstatus(ndr_err);
812         }
813
814         ndr_err = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, auth);
815         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
816                 talloc_free(ndr);
817                 return ndr_map_error2ntstatus(ndr_err);
818         }
819
820         if (check_pad && pad != auth->auth_pad_length) {
821                 DEBUG(1,(__location__ ": WARNING: pad length mismatch. Calculated %u  got %u\n",
822                          (unsigned)pad, (unsigned)auth->auth_pad_length));
823         }
824
825         DEBUG(6,(__location__ ": auth_pad_length %u\n",
826                  (unsigned)auth->auth_pad_length));
827
828         talloc_steal(mem_ctx, auth->credentials.data);
829         talloc_free(ndr);
830
831         return NT_STATUS_OK;
832 }
833
834