~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source4/rpc_server/dcerpc_server.c

  • Committer: Chuck Short
  • Date: 2010-09-28 20:38:39 UTC
  • Revision ID: zulcss@ubuntu.com-20100928203839-pgjulytsi9ue63x1
Initial version

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* 
 
2
   Unix SMB/CIFS implementation.
 
3
 
 
4
   server side dcerpc core code
 
5
 
 
6
   Copyright (C) Andrew Tridgell 2003-2005
 
7
   Copyright (C) Stefan (metze) Metzmacher 2004-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 3 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, see <http://www.gnu.org/licenses/>.
 
21
*/
 
22
 
 
23
#include "includes.h"
 
24
#include "librpc/gen_ndr/ndr_dcerpc.h"
 
25
#include "auth/auth.h"
 
26
#include "auth/gensec/gensec.h"
 
27
#include "../lib/util/dlinklist.h"
 
28
#include "rpc_server/dcerpc_server.h"
 
29
#include "rpc_server/dcerpc_server_proto.h"
 
30
#include "librpc/rpc/dcerpc_proto.h"
 
31
#include "lib/events/events.h"
 
32
#include "smbd/service_task.h"
 
33
#include "smbd/service_stream.h"
 
34
#include "smbd/service.h"
 
35
#include "system/filesys.h"
 
36
#include "libcli/security/security.h"
 
37
#include "param/param.h"
 
38
 
 
39
#define SAMBA_ASSOC_GROUP 0x12345678
 
40
 
 
41
extern const struct dcesrv_interface dcesrv_mgmt_interface;
 
42
 
 
43
/*
 
44
  see if two endpoints match
 
45
*/
 
46
static bool endpoints_match(const struct dcerpc_binding *ep1,
 
47
                            const struct dcerpc_binding *ep2)
 
48
{
 
49
        if (ep1->transport != ep2->transport) {
 
50
                return false;
 
51
        }
 
52
 
 
53
        if (!ep1->endpoint || !ep2->endpoint) {
 
54
                return ep1->endpoint == ep2->endpoint;
 
55
        }
 
56
 
 
57
        if (strcasecmp(ep1->endpoint, ep2->endpoint) != 0) 
 
58
                return false;
 
59
 
 
60
        return true;
 
61
}
 
62
 
 
63
/*
 
64
  find an endpoint in the dcesrv_context
 
65
*/
 
66
static struct dcesrv_endpoint *find_endpoint(struct dcesrv_context *dce_ctx,
 
67
                                             const struct dcerpc_binding *ep_description)
 
68
{
 
69
        struct dcesrv_endpoint *ep;
 
70
        for (ep=dce_ctx->endpoint_list; ep; ep=ep->next) {
 
71
                if (endpoints_match(ep->ep_description, ep_description)) {
 
72
                        return ep;
 
73
                }
 
74
        }
 
75
        return NULL;
 
76
}
 
77
 
 
78
/*
 
79
  find a registered context_id from a bind or alter_context
 
80
*/
 
81
static struct dcesrv_connection_context *dcesrv_find_context(struct dcesrv_connection *conn, 
 
82
                                                                   uint32_t context_id)
 
83
{
 
84
        struct dcesrv_connection_context *c;
 
85
        for (c=conn->contexts;c;c=c->next) {
 
86
                if (c->context_id == context_id) return c;
 
87
        }
 
88
        return NULL;
 
89
}
 
90
 
 
91
/*
 
92
  see if a uuid and if_version match to an interface
 
93
*/
 
94
static bool interface_match(const struct dcesrv_interface *if1,
 
95
                                                        const struct dcesrv_interface *if2)
 
96
{
 
97
        return (if1->syntax_id.if_version == if2->syntax_id.if_version && 
 
98
                        GUID_equal(&if1->syntax_id.uuid, &if2->syntax_id.uuid));
 
99
}
 
100
 
 
101
/*
 
102
  find the interface operations on an endpoint
 
103
*/
 
104
static const struct dcesrv_interface *find_interface(const struct dcesrv_endpoint *endpoint,
 
105
                                                     const struct dcesrv_interface *iface)
 
106
{
 
107
        struct dcesrv_if_list *ifl;
 
108
        for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) {
 
109
                if (interface_match(&(ifl->iface), iface)) {
 
110
                        return &(ifl->iface);
 
111
                }
 
112
        }
 
113
        return NULL;
 
114
}
 
115
 
 
116
/*
 
117
  see if a uuid and if_version match to an interface
 
118
*/
 
119
static bool interface_match_by_uuid(const struct dcesrv_interface *iface,
 
120
                                    const struct GUID *uuid, uint32_t if_version)
 
121
{
 
122
        return (iface->syntax_id.if_version == if_version && 
 
123
                        GUID_equal(&iface->syntax_id.uuid, uuid));
 
124
}
 
125
 
 
126
/*
 
127
  find the interface operations on an endpoint by uuid
 
128
*/
 
129
static const struct dcesrv_interface *find_interface_by_uuid(const struct dcesrv_endpoint *endpoint,
 
130
                                                             const struct GUID *uuid, uint32_t if_version)
 
131
{
 
132
        struct dcesrv_if_list *ifl;
 
133
        for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) {
 
134
                if (interface_match_by_uuid(&(ifl->iface), uuid, if_version)) {
 
135
                        return &(ifl->iface);
 
136
                }
 
137
        }
 
138
        return NULL;
 
139
}
 
140
 
 
141
/*
 
142
  find the earlier parts of a fragmented call awaiting reassembily
 
143
*/
 
144
static struct dcesrv_call_state *dcesrv_find_fragmented_call(struct dcesrv_connection *dce_conn, uint16_t call_id)
 
145
{
 
146
        struct dcesrv_call_state *c;
 
147
        for (c=dce_conn->incoming_fragmented_call_list;c;c=c->next) {
 
148
                if (c->pkt.call_id == call_id) {
 
149
                        return c;
 
150
                }
 
151
        }
 
152
        return NULL;
 
153
}
 
154
 
 
155
/*
 
156
  register an interface on an endpoint
 
157
*/
 
158
_PUBLIC_ NTSTATUS dcesrv_interface_register(struct dcesrv_context *dce_ctx,
 
159
                                   const char *ep_name,
 
160
                                   const struct dcesrv_interface *iface,
 
161
                                   const struct security_descriptor *sd)
 
162
{
 
163
        struct dcesrv_endpoint *ep;
 
164
        struct dcesrv_if_list *ifl;
 
165
        struct dcerpc_binding *binding;
 
166
        bool add_ep = false;
 
167
        NTSTATUS status;
 
168
        
 
169
        status = dcerpc_parse_binding(dce_ctx, ep_name, &binding);
 
170
 
 
171
        if (NT_STATUS_IS_ERR(status)) {
 
172
                DEBUG(0, ("Trouble parsing binding string '%s'\n", ep_name));
 
173
                return status;
 
174
        }
 
175
 
 
176
        /* check if this endpoint exists
 
177
         */
 
178
        if ((ep=find_endpoint(dce_ctx, binding))==NULL) {
 
179
                ep = talloc(dce_ctx, struct dcesrv_endpoint);
 
180
                if (!ep) {
 
181
                        return NT_STATUS_NO_MEMORY;
 
182
                }
 
183
                ZERO_STRUCTP(ep);
 
184
                ep->ep_description = talloc_reference(ep, binding);
 
185
                add_ep = true;
 
186
 
 
187
                /* add mgmt interface */
 
188
                ifl = talloc(dce_ctx, struct dcesrv_if_list);
 
189
                if (!ifl) {
 
190
                        return NT_STATUS_NO_MEMORY;
 
191
                }
 
192
 
 
193
                memcpy(&(ifl->iface), &dcesrv_mgmt_interface, 
 
194
                           sizeof(struct dcesrv_interface));
 
195
 
 
196
                DLIST_ADD(ep->interface_list, ifl);
 
197
        }
 
198
 
 
199
        /* see if the interface is already registered on te endpoint */
 
200
        if (find_interface(ep, iface)!=NULL) {
 
201
                DEBUG(0,("dcesrv_interface_register: interface '%s' already registered on endpoint '%s'\n",
 
202
                        iface->name, ep_name));
 
203
                return NT_STATUS_OBJECT_NAME_COLLISION;
 
204
        }
 
205
 
 
206
        /* talloc a new interface list element */
 
207
        ifl = talloc(dce_ctx, struct dcesrv_if_list);
 
208
        if (!ifl) {
 
209
                return NT_STATUS_NO_MEMORY;
 
210
        }
 
211
 
 
212
        /* copy the given interface struct to the one on the endpoints interface list */
 
213
        memcpy(&(ifl->iface),iface, sizeof(struct dcesrv_interface));
 
214
 
 
215
        /* if we have a security descriptor given,
 
216
         * we should see if we can set it up on the endpoint
 
217
         */
 
218
        if (sd != NULL) {
 
219
                /* if there's currently no security descriptor given on the endpoint
 
220
                 * we try to set it
 
221
                 */
 
222
                if (ep->sd == NULL) {
 
223
                        ep->sd = security_descriptor_copy(dce_ctx, sd);
 
224
                }
 
225
 
 
226
                /* if now there's no security descriptor given on the endpoint
 
227
                 * something goes wrong, either we failed to copy the security descriptor
 
228
                 * or there was already one on the endpoint
 
229
                 */
 
230
                if (ep->sd != NULL) {
 
231
                        DEBUG(0,("dcesrv_interface_register: interface '%s' failed to setup a security descriptor\n"
 
232
                                 "                           on endpoint '%s'\n",
 
233
                                iface->name, ep_name));
 
234
                        if (add_ep) free(ep);
 
235
                        free(ifl);
 
236
                        return NT_STATUS_OBJECT_NAME_COLLISION;
 
237
                }
 
238
        }
 
239
 
 
240
        /* finally add the interface on the endpoint */
 
241
        DLIST_ADD(ep->interface_list, ifl);
 
242
 
 
243
        /* if it's a new endpoint add it to the dcesrv_context */
 
244
        if (add_ep) {
 
245
                DLIST_ADD(dce_ctx->endpoint_list, ep);
 
246
        }
 
247
 
 
248
        DEBUG(4,("dcesrv_interface_register: interface '%s' registered on endpoint '%s'\n",
 
249
                iface->name, ep_name));
 
250
 
 
251
        return NT_STATUS_OK;
 
252
}
 
253
 
 
254
NTSTATUS dcesrv_inherited_session_key(struct dcesrv_connection *p,
 
255
                                      DATA_BLOB *session_key)
 
256
{
 
257
        if (p->auth_state.session_info->session_key.length) {
 
258
                *session_key = p->auth_state.session_info->session_key;
 
259
                return NT_STATUS_OK;
 
260
        }
 
261
        return NT_STATUS_NO_USER_SESSION_KEY;
 
262
}
 
263
 
 
264
NTSTATUS dcesrv_generic_session_key(struct dcesrv_connection *p,
 
265
                                    DATA_BLOB *session_key)
 
266
{
 
267
        /* this took quite a few CPU cycles to find ... */
 
268
        session_key->data = discard_const_p(uint8_t, "SystemLibraryDTC");
 
269
        session_key->length = 16;
 
270
        return NT_STATUS_OK;
 
271
}
 
272
 
 
273
/*
 
274
  fetch the user session key - may be default (above) or the SMB session key
 
275
 
 
276
  The key is always truncated to 16 bytes 
 
277
*/
 
278
_PUBLIC_ NTSTATUS dcesrv_fetch_session_key(struct dcesrv_connection *p,
 
279
                                  DATA_BLOB *session_key)
 
280
{
 
281
        NTSTATUS status = p->auth_state.session_key(p, session_key);
 
282
        if (!NT_STATUS_IS_OK(status)) {
 
283
                return status;
 
284
        }
 
285
 
 
286
        session_key->length = MIN(session_key->length, 16);
 
287
 
 
288
        return NT_STATUS_OK;
 
289
}
 
290
 
 
291
/*
 
292
  connect to a dcerpc endpoint
 
293
*/
 
294
_PUBLIC_ NTSTATUS dcesrv_endpoint_connect(struct dcesrv_context *dce_ctx,
 
295
                                 TALLOC_CTX *mem_ctx,
 
296
                                 const struct dcesrv_endpoint *ep,
 
297
                                 struct auth_session_info *session_info,
 
298
                                 struct tevent_context *event_ctx,
 
299
                                 struct messaging_context *msg_ctx,
 
300
                                 struct server_id server_id,
 
301
                                 uint32_t state_flags,
 
302
                                 struct dcesrv_connection **_p)
 
303
{
 
304
        struct dcesrv_connection *p;
 
305
 
 
306
        if (!session_info) {
 
307
                return NT_STATUS_ACCESS_DENIED;
 
308
        }
 
309
 
 
310
        p = talloc(mem_ctx, struct dcesrv_connection);
 
311
        NT_STATUS_HAVE_NO_MEMORY(p);
 
312
 
 
313
        if (!talloc_reference(p, session_info)) {
 
314
                talloc_free(p);
 
315
                return NT_STATUS_NO_MEMORY;
 
316
        }
 
317
 
 
318
        p->dce_ctx = dce_ctx;
 
319
        p->endpoint = ep;
 
320
        p->contexts = NULL;
 
321
        p->call_list = NULL;
 
322
        p->packet_log_dir = lp_lockdir(dce_ctx->lp_ctx);
 
323
        p->incoming_fragmented_call_list = NULL;
 
324
        p->pending_call_list = NULL;
 
325
        p->cli_max_recv_frag = 0;
 
326
        p->partial_input = data_blob(NULL, 0);
 
327
        p->auth_state.auth_info = NULL;
 
328
        p->auth_state.gensec_security = NULL;
 
329
        p->auth_state.session_info = session_info;
 
330
        p->auth_state.session_key = dcesrv_generic_session_key;
 
331
        p->event_ctx = event_ctx;
 
332
        p->msg_ctx = msg_ctx;
 
333
        p->server_id = server_id;
 
334
        p->processing = false;
 
335
        p->state_flags = state_flags;
 
336
        ZERO_STRUCT(p->transport);
 
337
 
 
338
        *_p = p;
 
339
        return NT_STATUS_OK;
 
340
}
 
341
 
 
342
/*
 
343
  search and connect to a dcerpc endpoint
 
344
*/
 
345
_PUBLIC_ NTSTATUS dcesrv_endpoint_search_connect(struct dcesrv_context *dce_ctx,
 
346
                                        TALLOC_CTX *mem_ctx,
 
347
                                        const struct dcerpc_binding *ep_description,
 
348
                                        struct auth_session_info *session_info,
 
349
                                        struct tevent_context *event_ctx,
 
350
                                        struct messaging_context *msg_ctx,
 
351
                                        struct server_id server_id,
 
352
                                        uint32_t state_flags,
 
353
                                        struct dcesrv_connection **dce_conn_p)
 
354
{
 
355
        NTSTATUS status;
 
356
        const struct dcesrv_endpoint *ep;
 
357
 
 
358
        /* make sure this endpoint exists */
 
359
        ep = find_endpoint(dce_ctx, ep_description);
 
360
        if (!ep) {
 
361
                return NT_STATUS_OBJECT_NAME_NOT_FOUND;
 
362
        }
 
363
 
 
364
        status = dcesrv_endpoint_connect(dce_ctx, mem_ctx, ep, session_info,
 
365
                                         event_ctx, msg_ctx, server_id,
 
366
                                         state_flags, dce_conn_p);
 
367
        NT_STATUS_NOT_OK_RETURN(status);
 
368
 
 
369
        (*dce_conn_p)->auth_state.session_key = dcesrv_inherited_session_key;
 
370
 
 
371
        /* TODO: check security descriptor of the endpoint here 
 
372
         *       if it's a smb named pipe
 
373
         *       if it's failed free dce_conn_p
 
374
         */
 
375
 
 
376
        return NT_STATUS_OK;
 
377
}
 
378
 
 
379
 
 
380
static void dcesrv_init_hdr(struct ncacn_packet *pkt, bool bigendian)
 
381
{
 
382
        pkt->rpc_vers = 5;
 
383
        pkt->rpc_vers_minor = 0;
 
384
        if (bigendian) {
 
385
                pkt->drep[0] = 0;
 
386
        } else {
 
387
                pkt->drep[0] = DCERPC_DREP_LE;
 
388
        }
 
389
        pkt->drep[1] = 0;
 
390
        pkt->drep[2] = 0;
 
391
        pkt->drep[3] = 0;
 
392
}
 
393
 
 
394
/*
 
395
  move a call from an existing linked list to the specified list. This
 
396
  prevents bugs where we forget to remove the call from a previous
 
397
  list when moving it.
 
398
 */
 
399
static void dcesrv_call_set_list(struct dcesrv_call_state *call, 
 
400
                                 enum dcesrv_call_list list)
 
401
{
 
402
        switch (call->list) {
 
403
        case DCESRV_LIST_NONE:
 
404
                break;
 
405
        case DCESRV_LIST_CALL_LIST:
 
406
                DLIST_REMOVE(call->conn->call_list, call);
 
407
                break;
 
408
        case DCESRV_LIST_FRAGMENTED_CALL_LIST:
 
409
                DLIST_REMOVE(call->conn->incoming_fragmented_call_list, call);
 
410
                break;
 
411
        case DCESRV_LIST_PENDING_CALL_LIST:
 
412
                DLIST_REMOVE(call->conn->pending_call_list, call);
 
413
                break;
 
414
        }
 
415
        call->list = list;
 
416
        switch (list) {
 
417
        case DCESRV_LIST_NONE:
 
418
                break;
 
419
        case DCESRV_LIST_CALL_LIST:
 
420
                DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
 
421
                break;
 
422
        case DCESRV_LIST_FRAGMENTED_CALL_LIST:
 
423
                DLIST_ADD_END(call->conn->incoming_fragmented_call_list, call, struct dcesrv_call_state *);
 
424
                break;
 
425
        case DCESRV_LIST_PENDING_CALL_LIST:
 
426
                DLIST_ADD_END(call->conn->pending_call_list, call, struct dcesrv_call_state *);
 
427
                break;
 
428
        }
 
429
}
 
430
 
 
431
/*
 
432
  return a dcerpc fault
 
433
*/
 
434
static NTSTATUS dcesrv_fault(struct dcesrv_call_state *call, uint32_t fault_code)
 
435
{
 
436
        struct ncacn_packet pkt;
 
437
        struct data_blob_list_item *rep;
 
438
        uint8_t zeros[4];
 
439
        NTSTATUS status;
 
440
 
 
441
        /* setup a bind_ack */
 
442
        dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
 
443
        pkt.auth_length = 0;
 
444
        pkt.call_id = call->pkt.call_id;
 
445
        pkt.ptype = DCERPC_PKT_FAULT;
 
446
        pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
 
447
        pkt.u.fault.alloc_hint = 0;
 
448
        pkt.u.fault.context_id = 0;
 
449
        pkt.u.fault.cancel_count = 0;
 
450
        pkt.u.fault.status = fault_code;
 
451
 
 
452
        ZERO_STRUCT(zeros);
 
453
        pkt.u.fault._pad = data_blob_const(zeros, sizeof(zeros));
 
454
 
 
455
        rep = talloc(call, struct data_blob_list_item);
 
456
        if (!rep) {
 
457
                return NT_STATUS_NO_MEMORY;
 
458
        }
 
459
 
 
460
        status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, NULL);
 
461
        if (!NT_STATUS_IS_OK(status)) {
 
462
                return status;
 
463
        }
 
464
 
 
465
        dcerpc_set_frag_length(&rep->blob, rep->blob.length);
 
466
 
 
467
        DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
 
468
        dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
 
469
 
 
470
        return NT_STATUS_OK;    
 
471
}
 
472
 
 
473
 
 
474
/*
 
475
  return a dcerpc bind_nak
 
476
*/
 
477
static NTSTATUS dcesrv_bind_nak(struct dcesrv_call_state *call, uint32_t reason)
 
478
{
 
479
        struct ncacn_packet pkt;
 
480
        struct data_blob_list_item *rep;
 
481
        NTSTATUS status;
 
482
 
 
483
        /* setup a bind_nak */
 
484
        dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
 
485
        pkt.auth_length = 0;
 
486
        pkt.call_id = call->pkt.call_id;
 
487
        pkt.ptype = DCERPC_PKT_BIND_NAK;
 
488
        pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
 
489
        pkt.u.bind_nak.reject_reason = reason;
 
490
        if (pkt.u.bind_nak.reject_reason == DECRPC_BIND_PROTOCOL_VERSION_NOT_SUPPORTED) {
 
491
                pkt.u.bind_nak.versions.v.num_versions = 0;
 
492
        }
 
493
 
 
494
        rep = talloc(call, struct data_blob_list_item);
 
495
        if (!rep) {
 
496
                return NT_STATUS_NO_MEMORY;
 
497
        }
 
498
 
 
499
        status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, NULL);
 
500
        if (!NT_STATUS_IS_OK(status)) {
 
501
                return status;
 
502
        }
 
503
 
 
504
        dcerpc_set_frag_length(&rep->blob, rep->blob.length);
 
505
 
 
506
        DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
 
507
        dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
 
508
 
 
509
        return NT_STATUS_OK;    
 
510
}
 
511
 
 
512
static int dcesrv_connection_context_destructor(struct dcesrv_connection_context *c)
 
513
{
 
514
        DLIST_REMOVE(c->conn->contexts, c);
 
515
 
 
516
        if (c->iface) {
 
517
                c->iface->unbind(c, c->iface);
 
518
        }
 
519
 
 
520
        return 0;
 
521
}
 
522
 
 
523
/*
 
524
  handle a bind request
 
525
*/
 
526
static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
 
527
{
 
528
        uint32_t if_version, transfer_syntax_version;
 
529
        struct GUID uuid, *transfer_syntax_uuid;
 
530
        struct ncacn_packet pkt;
 
531
        struct data_blob_list_item *rep;
 
532
        NTSTATUS status;
 
533
        uint32_t result=0, reason=0;
 
534
        uint32_t context_id;
 
535
        const struct dcesrv_interface *iface;
 
536
        uint32_t extra_flags = 0;
 
537
 
 
538
        /*
 
539
         * Association groups allow policy handles to be shared across
 
540
         * multiple client connections.  We don't implement this yet.
 
541
         *
 
542
         * So we just allow 0 if the client wants to create a new
 
543
         * association group.
 
544
         *
 
545
         * And we allow the 0x12345678 value, we give away as
 
546
         * assoc_group_id back to the clients
 
547
         */
 
548
        if (call->pkt.u.bind.assoc_group_id != 0 &&
 
549
            lp_parm_bool(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv","assoc group checking", true) &&
 
550
            call->pkt.u.bind.assoc_group_id != SAMBA_ASSOC_GROUP) {
 
551
                return dcesrv_bind_nak(call, 0);        
 
552
        }
 
553
 
 
554
        if (call->pkt.u.bind.num_contexts < 1 ||
 
555
            call->pkt.u.bind.ctx_list[0].num_transfer_syntaxes < 1) {
 
556
                return dcesrv_bind_nak(call, 0);
 
557
        }
 
558
 
 
559
        context_id = call->pkt.u.bind.ctx_list[0].context_id;
 
560
 
 
561
        /* you can't bind twice on one context */
 
562
        if (dcesrv_find_context(call->conn, context_id) != NULL) {
 
563
                return dcesrv_bind_nak(call, 0);
 
564
        }
 
565
 
 
566
        if_version = call->pkt.u.bind.ctx_list[0].abstract_syntax.if_version;
 
567
        uuid = call->pkt.u.bind.ctx_list[0].abstract_syntax.uuid;
 
568
 
 
569
        transfer_syntax_version = call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].if_version;
 
570
        transfer_syntax_uuid = &call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].uuid;
 
571
        if (!GUID_equal(&ndr_transfer_syntax.uuid, transfer_syntax_uuid) != 0 ||
 
572
            ndr_transfer_syntax.if_version != transfer_syntax_version) {
 
573
                char *uuid_str = GUID_string(call, transfer_syntax_uuid);
 
574
                /* we only do NDR encoded dcerpc */
 
575
                DEBUG(0,("Non NDR transfer syntax requested - %s\n", uuid_str));
 
576
                talloc_free(uuid_str);
 
577
                return dcesrv_bind_nak(call, 0);
 
578
        }
 
579
 
 
580
        iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
 
581
        if (iface == NULL) {
 
582
                char *uuid_str = GUID_string(call, &uuid);
 
583
                DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
 
584
                talloc_free(uuid_str);
 
585
 
 
586
                /* we don't know about that interface */
 
587
                result = DCERPC_BIND_PROVIDER_REJECT;
 
588
                reason = DCERPC_BIND_REASON_ASYNTAX;            
 
589
        }
 
590
 
 
591
        if (iface) {
 
592
                /* add this context to the list of available context_ids */
 
593
                struct dcesrv_connection_context *context = talloc(call->conn, 
 
594
                                                                   struct dcesrv_connection_context);
 
595
                if (context == NULL) {
 
596
                        return dcesrv_bind_nak(call, 0);
 
597
                }
 
598
                context->conn = call->conn;
 
599
                context->iface = iface;
 
600
                context->context_id = context_id;
 
601
                /*
 
602
                 * we need to send a non zero assoc_group_id here to make longhorn happy,
 
603
                 * it also matches samba3
 
604
                 */
 
605
                context->assoc_group_id = SAMBA_ASSOC_GROUP;
 
606
                context->private_data = NULL;
 
607
                context->handles = NULL;
 
608
                DLIST_ADD(call->conn->contexts, context);
 
609
                call->context = context;
 
610
                talloc_set_destructor(context, dcesrv_connection_context_destructor);
 
611
 
 
612
                status = iface->bind(call, iface);
 
613
                if (!NT_STATUS_IS_OK(status)) {
 
614
                        char *uuid_str = GUID_string(call, &uuid);
 
615
                        DEBUG(2,("Request for dcerpc interface %s/%d rejected: %s\n",
 
616
                                 uuid_str, if_version, nt_errstr(status)));
 
617
                        talloc_free(uuid_str);
 
618
                        /* we don't want to trigger the iface->unbind() hook */
 
619
                        context->iface = NULL;
 
620
                        talloc_free(call->context);
 
621
                        call->context = NULL;
 
622
                        return dcesrv_bind_nak(call, 0);
 
623
                }
 
624
        }
 
625
 
 
626
        if (call->conn->cli_max_recv_frag == 0) {
 
627
                call->conn->cli_max_recv_frag = call->pkt.u.bind.max_recv_frag;
 
628
        }
 
629
 
 
630
        if ((call->pkt.pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN) &&
 
631
            lp_parm_bool(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv","header signing", false)) {
 
632
                call->conn->state_flags |= DCESRV_CALL_STATE_FLAG_HEADER_SIGNING;
 
633
                extra_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
 
634
        }
 
635
 
 
636
        /* handle any authentication that is being requested */
 
637
        if (!dcesrv_auth_bind(call)) {
 
638
                talloc_free(call->context);
 
639
                call->context = NULL;
 
640
                return dcesrv_bind_nak(call, DCERPC_BIND_REASON_INVALID_AUTH_TYPE);
 
641
        }
 
642
 
 
643
        /* setup a bind_ack */
 
644
        dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
 
645
        pkt.auth_length = 0;
 
646
        pkt.call_id = call->pkt.call_id;
 
647
        pkt.ptype = DCERPC_PKT_BIND_ACK;
 
648
        pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST | extra_flags;
 
649
        pkt.u.bind_ack.max_xmit_frag = 0x2000;
 
650
        pkt.u.bind_ack.max_recv_frag = 0x2000;
 
651
 
 
652
        /*
 
653
          make it possible for iface->bind() to specify the assoc_group_id
 
654
          This helps the openchange mapiproxy plugin to work correctly.
 
655
          
 
656
          metze
 
657
        */
 
658
        if (call->context) {
 
659
                pkt.u.bind_ack.assoc_group_id = call->context->assoc_group_id;
 
660
        } else {
 
661
                /* we better pick something - this chosen so as to send a non zero assoc_group_id (matching windows), it also matches samba3 */
 
662
                pkt.u.bind_ack.assoc_group_id = SAMBA_ASSOC_GROUP;
 
663
        }
 
664
 
 
665
        if (iface) {
 
666
                /* FIXME: Use pipe name as specified by endpoint instead of interface name */
 
667
                pkt.u.bind_ack.secondary_address = talloc_asprintf(call, "\\PIPE\\%s", iface->name);
 
668
        } else {
 
669
                pkt.u.bind_ack.secondary_address = "";
 
670
        }
 
671
        pkt.u.bind_ack.num_results = 1;
 
672
        pkt.u.bind_ack.ctx_list = talloc(call, struct dcerpc_ack_ctx);
 
673
        if (!pkt.u.bind_ack.ctx_list) {
 
674
                talloc_free(call->context);
 
675
                call->context = NULL;
 
676
                return NT_STATUS_NO_MEMORY;
 
677
        }
 
678
        pkt.u.bind_ack.ctx_list[0].result = result;
 
679
        pkt.u.bind_ack.ctx_list[0].reason = reason;
 
680
        pkt.u.bind_ack.ctx_list[0].syntax = ndr_transfer_syntax;
 
681
        pkt.u.bind_ack.auth_info = data_blob(NULL, 0);
 
682
 
 
683
        status = dcesrv_auth_bind_ack(call, &pkt);
 
684
        if (!NT_STATUS_IS_OK(status)) {
 
685
                talloc_free(call->context);
 
686
                call->context = NULL;
 
687
                return dcesrv_bind_nak(call, 0);
 
688
        }
 
689
 
 
690
        rep = talloc(call, struct data_blob_list_item);
 
691
        if (!rep) {
 
692
                talloc_free(call->context);
 
693
                call->context = NULL;
 
694
                return NT_STATUS_NO_MEMORY;
 
695
        }
 
696
 
 
697
        status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, call->conn->auth_state.auth_info);
 
698
        if (!NT_STATUS_IS_OK(status)) {
 
699
                talloc_free(call->context);
 
700
                call->context = NULL;
 
701
                return status;
 
702
        }
 
703
 
 
704
        dcerpc_set_frag_length(&rep->blob, rep->blob.length);
 
705
 
 
706
        DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
 
707
        dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
 
708
 
 
709
        return NT_STATUS_OK;
 
710
}
 
711
 
 
712
 
 
713
/*
 
714
  handle a auth3 request
 
715
*/
 
716
static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call)
 
717
{
 
718
        /* handle the auth3 in the auth code */
 
719
        if (!dcesrv_auth_auth3(call)) {
 
720
                return dcesrv_fault(call, DCERPC_FAULT_OTHER);
 
721
        }
 
722
 
 
723
        talloc_free(call);
 
724
 
 
725
        /* we don't send a reply to a auth3 request, except by a
 
726
           fault */
 
727
        return NT_STATUS_OK;
 
728
}
 
729
 
 
730
 
 
731
/*
 
732
  handle a bind request
 
733
*/
 
734
static NTSTATUS dcesrv_alter_new_context(struct dcesrv_call_state *call, uint32_t context_id)
 
735
{
 
736
        uint32_t if_version, transfer_syntax_version;
 
737
        struct dcesrv_connection_context *context;
 
738
        const struct dcesrv_interface *iface;
 
739
        struct GUID uuid, *transfer_syntax_uuid;
 
740
        NTSTATUS status;
 
741
 
 
742
        if_version = call->pkt.u.alter.ctx_list[0].abstract_syntax.if_version;
 
743
        uuid = call->pkt.u.alter.ctx_list[0].abstract_syntax.uuid;
 
744
 
 
745
        transfer_syntax_version = call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].if_version;
 
746
        transfer_syntax_uuid = &call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].uuid;
 
747
        if (!GUID_equal(transfer_syntax_uuid, &ndr_transfer_syntax.uuid) ||
 
748
            ndr_transfer_syntax.if_version != transfer_syntax_version) {
 
749
                /* we only do NDR encoded dcerpc */
 
750
                return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
 
751
        }
 
752
 
 
753
        iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
 
754
        if (iface == NULL) {
 
755
                char *uuid_str = GUID_string(call, &uuid);
 
756
                DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
 
757
                talloc_free(uuid_str);
 
758
                return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
 
759
        }
 
760
 
 
761
        /* add this context to the list of available context_ids */
 
762
        context = talloc(call->conn, struct dcesrv_connection_context);
 
763
        if (context == NULL) {
 
764
                return NT_STATUS_NO_MEMORY;
 
765
        }
 
766
        context->conn = call->conn;
 
767
        context->iface = iface;
 
768
        context->context_id = context_id;
 
769
        context->assoc_group_id = SAMBA_ASSOC_GROUP;
 
770
        context->private_data = NULL;
 
771
        context->handles = NULL;
 
772
        DLIST_ADD(call->conn->contexts, context);
 
773
        call->context = context;
 
774
        talloc_set_destructor(context, dcesrv_connection_context_destructor);
 
775
 
 
776
        status = iface->bind(call, iface);
 
777
        if (!NT_STATUS_IS_OK(status)) {
 
778
                /* we don't want to trigger the iface->unbind() hook */
 
779
                context->iface = NULL;
 
780
                talloc_free(context);
 
781
                call->context = NULL;
 
782
                return status;
 
783
        }
 
784
 
 
785
        return NT_STATUS_OK;
 
786
}
 
787
 
 
788
 
 
789
/*
 
790
  handle a alter context request
 
791
*/
 
792
static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call)
 
793
{
 
794
        struct ncacn_packet pkt;
 
795
        struct data_blob_list_item *rep;
 
796
        NTSTATUS status;
 
797
        uint32_t result=0, reason=0;
 
798
        uint32_t context_id;
 
799
 
 
800
        /* handle any authentication that is being requested */
 
801
        if (!dcesrv_auth_alter(call)) {
 
802
                /* TODO: work out the right reject code */
 
803
                result = DCERPC_BIND_PROVIDER_REJECT;
 
804
                reason = DCERPC_BIND_REASON_ASYNTAX;            
 
805
        }
 
806
 
 
807
        context_id = call->pkt.u.alter.ctx_list[0].context_id;
 
808
 
 
809
        /* see if they are asking for a new interface */
 
810
        if (result == 0) {
 
811
                call->context = dcesrv_find_context(call->conn, context_id);
 
812
                if (!call->context) {
 
813
                        status = dcesrv_alter_new_context(call, context_id);
 
814
                        if (!NT_STATUS_IS_OK(status)) {
 
815
                                result = DCERPC_BIND_PROVIDER_REJECT;
 
816
                                reason = DCERPC_BIND_REASON_ASYNTAX;
 
817
                        }
 
818
                }
 
819
        }
 
820
 
 
821
        if (result == 0 &&
 
822
            call->pkt.u.alter.assoc_group_id != 0 &&
 
823
            lp_parm_bool(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv","assoc group checking", true) &&
 
824
            call->pkt.u.alter.assoc_group_id != call->context->assoc_group_id) {
 
825
                /* TODO: work out what to return here */
 
826
                result = DCERPC_BIND_PROVIDER_REJECT;
 
827
                reason = DCERPC_BIND_REASON_ASYNTAX;
 
828
        }
 
829
 
 
830
        /* setup a alter_resp */
 
831
        dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
 
832
        pkt.auth_length = 0;
 
833
        pkt.call_id = call->pkt.call_id;
 
834
        pkt.ptype = DCERPC_PKT_ALTER_RESP;
 
835
        pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
 
836
        pkt.u.alter_resp.max_xmit_frag = 0x2000;
 
837
        pkt.u.alter_resp.max_recv_frag = 0x2000;
 
838
        if (result == 0) {
 
839
                pkt.u.alter_resp.assoc_group_id = call->context->assoc_group_id;
 
840
        } else {
 
841
                pkt.u.alter_resp.assoc_group_id = 0;
 
842
        }
 
843
        pkt.u.alter_resp.num_results = 1;
 
844
        pkt.u.alter_resp.ctx_list = talloc_array(call, struct dcerpc_ack_ctx, 1);
 
845
        if (!pkt.u.alter_resp.ctx_list) {
 
846
                return NT_STATUS_NO_MEMORY;
 
847
        }
 
848
        pkt.u.alter_resp.ctx_list[0].result = result;
 
849
        pkt.u.alter_resp.ctx_list[0].reason = reason;
 
850
        pkt.u.alter_resp.ctx_list[0].syntax = ndr_transfer_syntax;
 
851
        pkt.u.alter_resp.auth_info = data_blob(NULL, 0);
 
852
        pkt.u.alter_resp.secondary_address = "";
 
853
 
 
854
        status = dcesrv_auth_alter_ack(call, &pkt);
 
855
        if (!NT_STATUS_IS_OK(status)) {
 
856
                if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)
 
857
                    || NT_STATUS_EQUAL(status, NT_STATUS_LOGON_FAILURE)
 
858
                    || NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)
 
859
                    || NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
 
860
                        return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
 
861
                }
 
862
                return dcesrv_fault(call, 0);
 
863
        }
 
864
 
 
865
        rep = talloc(call, struct data_blob_list_item);
 
866
        if (!rep) {
 
867
                return NT_STATUS_NO_MEMORY;
 
868
        }
 
869
 
 
870
        status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, call->conn->auth_state.auth_info);
 
871
        if (!NT_STATUS_IS_OK(status)) {
 
872
                return status;
 
873
        }
 
874
 
 
875
        dcerpc_set_frag_length(&rep->blob, rep->blob.length);
 
876
 
 
877
        DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
 
878
        dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
 
879
 
 
880
        return NT_STATUS_OK;
 
881
}
 
882
 
 
883
/*
 
884
  handle a dcerpc request packet
 
885
*/
 
886
static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
 
887
{
 
888
        struct ndr_pull *pull;
 
889
        NTSTATUS status;
 
890
        struct dcesrv_connection_context *context;
 
891
 
 
892
        /* if authenticated, and the mech we use can't do async replies, don't use them... */
 
893
        if (call->conn->auth_state.gensec_security && 
 
894
            !gensec_have_feature(call->conn->auth_state.gensec_security, GENSEC_FEATURE_ASYNC_REPLIES)) {
 
895
                call->state_flags &= ~DCESRV_CALL_STATE_FLAG_MAY_ASYNC;
 
896
        }
 
897
 
 
898
        context = dcesrv_find_context(call->conn, call->pkt.u.request.context_id);
 
899
        if (context == NULL) {
 
900
                return dcesrv_fault(call, DCERPC_FAULT_UNK_IF);
 
901
        }
 
902
 
 
903
        pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier, call,
 
904
                                  lp_iconv_convenience(call->conn->dce_ctx->lp_ctx));
 
905
        NT_STATUS_HAVE_NO_MEMORY(pull);
 
906
 
 
907
        pull->flags |= LIBNDR_FLAG_REF_ALLOC;
 
908
 
 
909
        call->context   = context;
 
910
        call->ndr_pull  = pull;
 
911
 
 
912
        if (!(call->pkt.drep[0] & DCERPC_DREP_LE)) {
 
913
                pull->flags |= LIBNDR_FLAG_BIGENDIAN;
 
914
        }
 
915
 
 
916
        /* unravel the NDR for the packet */
 
917
        status = context->iface->ndr_pull(call, call, pull, &call->r);
 
918
        if (!NT_STATUS_IS_OK(status)) {
 
919
                return dcesrv_fault(call, call->fault_code);
 
920
        }
 
921
 
 
922
        if (pull->offset != pull->data_size) {
 
923
                DEBUG(3,("Warning: %d extra bytes in incoming RPC request\n", 
 
924
                         pull->data_size - pull->offset));
 
925
                dump_data(10, pull->data+pull->offset, pull->data_size - pull->offset);
 
926
        }
 
927
 
 
928
        /* call the dispatch function */
 
929
        status = context->iface->dispatch(call, call, call->r);
 
930
        if (!NT_STATUS_IS_OK(status)) {
 
931
                DEBUG(5,("dcerpc fault in call %s:%02x - %s\n",
 
932
                         context->iface->name, 
 
933
                         call->pkt.u.request.opnum,
 
934
                         dcerpc_errstr(pull, call->fault_code)));
 
935
                return dcesrv_fault(call, call->fault_code);
 
936
        }
 
937
 
 
938
        /* add the call to the pending list */
 
939
        dcesrv_call_set_list(call, DCESRV_LIST_PENDING_CALL_LIST);
 
940
 
 
941
        if (call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) {
 
942
                return NT_STATUS_OK;
 
943
        }
 
944
 
 
945
        return dcesrv_reply(call);
 
946
}
 
947
 
 
948
_PUBLIC_ NTSTATUS dcesrv_reply(struct dcesrv_call_state *call)
 
949
{
 
950
        struct ndr_push *push;
 
951
        NTSTATUS status;
 
952
        DATA_BLOB stub;
 
953
        uint32_t total_length, chunk_size;
 
954
        struct dcesrv_connection_context *context = call->context;
 
955
        size_t sig_size = 0;
 
956
 
 
957
        /* call the reply function */
 
958
        status = context->iface->reply(call, call, call->r);
 
959
        if (!NT_STATUS_IS_OK(status)) {
 
960
                return dcesrv_fault(call, call->fault_code);
 
961
        }
 
962
 
 
963
        /* form the reply NDR */
 
964
        push = ndr_push_init_ctx(call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx));
 
965
        NT_STATUS_HAVE_NO_MEMORY(push);
 
966
 
 
967
        /* carry over the pointer count to the reply in case we are
 
968
           using full pointer. See NDR specification for full
 
969
           pointers */
 
970
        push->ptr_count = call->ndr_pull->ptr_count;
 
971
 
 
972
        if (lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx)) {
 
973
                push->flags |= LIBNDR_FLAG_BIGENDIAN;
 
974
        }
 
975
 
 
976
        status = context->iface->ndr_push(call, call, push, call->r);
 
977
        if (!NT_STATUS_IS_OK(status)) {
 
978
                return dcesrv_fault(call, call->fault_code);
 
979
        }
 
980
 
 
981
        stub = ndr_push_blob(push);
 
982
 
 
983
        total_length = stub.length;
 
984
 
 
985
        /* we can write a full max_recv_frag size, minus the dcerpc
 
986
           request header size */
 
987
        chunk_size = call->conn->cli_max_recv_frag;
 
988
        chunk_size -= DCERPC_REQUEST_LENGTH;
 
989
        if (call->conn->auth_state.auth_info &&
 
990
            call->conn->auth_state.gensec_security) {
 
991
                sig_size = gensec_sig_size(call->conn->auth_state.gensec_security,
 
992
                                           call->conn->cli_max_recv_frag);
 
993
                if (sig_size) {
 
994
                        chunk_size -= DCERPC_AUTH_TRAILER_LENGTH;
 
995
                        chunk_size -= sig_size;
 
996
                }
 
997
        }
 
998
        chunk_size -= (chunk_size % 16);
 
999
 
 
1000
        do {
 
1001
                uint32_t length;
 
1002
                struct data_blob_list_item *rep;
 
1003
                struct ncacn_packet pkt;
 
1004
 
 
1005
                rep = talloc(call, struct data_blob_list_item);
 
1006
                NT_STATUS_HAVE_NO_MEMORY(rep);
 
1007
 
 
1008
                length = MIN(chunk_size, stub.length);
 
1009
 
 
1010
                /* form the dcerpc response packet */
 
1011
                dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
 
1012
                pkt.auth_length = 0;
 
1013
                pkt.call_id = call->pkt.call_id;
 
1014
                pkt.ptype = DCERPC_PKT_RESPONSE;
 
1015
                pkt.pfc_flags = 0;
 
1016
                if (stub.length == total_length) {
 
1017
                        pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
 
1018
                }
 
1019
                if (length == stub.length) {
 
1020
                        pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
 
1021
                }
 
1022
                pkt.u.response.alloc_hint = stub.length;
 
1023
                pkt.u.response.context_id = call->pkt.u.request.context_id;
 
1024
                pkt.u.response.cancel_count = 0;
 
1025
                pkt.u.response.stub_and_verifier.data = stub.data;
 
1026
                pkt.u.response.stub_and_verifier.length = length;
 
1027
 
 
1028
                if (!dcesrv_auth_response(call, &rep->blob, sig_size, &pkt)) {
 
1029
                        return dcesrv_fault(call, DCERPC_FAULT_OTHER);          
 
1030
                }
 
1031
 
 
1032
                dcerpc_set_frag_length(&rep->blob, rep->blob.length);
 
1033
 
 
1034
                DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
 
1035
                
 
1036
                stub.data += length;
 
1037
                stub.length -= length;
 
1038
        } while (stub.length != 0);
 
1039
 
 
1040
        /* move the call from the pending to the finished calls list */
 
1041
        dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
 
1042
 
 
1043
        if (call->conn->call_list && call->conn->call_list->replies) {
 
1044
                if (call->conn->transport.report_output_data) {
 
1045
                        call->conn->transport.report_output_data(call->conn);
 
1046
                }
 
1047
        }
 
1048
 
 
1049
        return NT_STATUS_OK;
 
1050
}
 
1051
 
 
1052
_PUBLIC_ struct socket_address *dcesrv_connection_get_my_addr(struct dcesrv_connection *conn, TALLOC_CTX *mem_ctx)
 
1053
{
 
1054
        if (!conn->transport.get_my_addr) {
 
1055
                return NULL;
 
1056
        }
 
1057
 
 
1058
        return conn->transport.get_my_addr(conn, mem_ctx);
 
1059
}
 
1060
 
 
1061
_PUBLIC_ struct socket_address *dcesrv_connection_get_peer_addr(struct dcesrv_connection *conn, TALLOC_CTX *mem_ctx)
 
1062
{
 
1063
        if (!conn->transport.get_peer_addr) {
 
1064
                return NULL;
 
1065
        }
 
1066
 
 
1067
        return conn->transport.get_peer_addr(conn, mem_ctx);
 
1068
}
 
1069
 
 
1070
/*
 
1071
  work out if we have a full packet yet
 
1072
*/
 
1073
static bool dce_full_packet(const DATA_BLOB *data)
 
1074
{
 
1075
        if (data->length < DCERPC_FRAG_LEN_OFFSET+2) {
 
1076
                return false;
 
1077
        }
 
1078
        if (dcerpc_get_frag_length(data) > data->length) {
 
1079
                return false;
 
1080
        }
 
1081
        return true;
 
1082
}
 
1083
 
 
1084
/*
 
1085
  we might have consumed only part of our input - advance past that part
 
1086
*/
 
1087
static void dce_partial_advance(struct dcesrv_connection *dce_conn, uint32_t offset)
 
1088
{
 
1089
        DATA_BLOB blob;
 
1090
 
 
1091
        if (dce_conn->partial_input.length == offset) {
 
1092
                data_blob_free(&dce_conn->partial_input);
 
1093
                return;
 
1094
        }
 
1095
 
 
1096
        blob = dce_conn->partial_input;
 
1097
        dce_conn->partial_input = data_blob(blob.data + offset,
 
1098
                                            blob.length - offset);
 
1099
        data_blob_free(&blob);
 
1100
}
 
1101
 
 
1102
/*
 
1103
  remove the call from the right list when freed
 
1104
 */
 
1105
static int dcesrv_call_dequeue(struct dcesrv_call_state *call)
 
1106
{
 
1107
        dcesrv_call_set_list(call, DCESRV_LIST_NONE);
 
1108
        return 0;
 
1109
}
 
1110
 
 
1111
/*
 
1112
  process some input to a dcerpc endpoint server.
 
1113
*/
 
1114
NTSTATUS dcesrv_input_process(struct dcesrv_connection *dce_conn)
 
1115
{
 
1116
        struct ndr_pull *ndr;
 
1117
        enum ndr_err_code ndr_err;
 
1118
        NTSTATUS status;
 
1119
        struct dcesrv_call_state *call;
 
1120
        DATA_BLOB blob;
 
1121
 
 
1122
        call = talloc_zero(dce_conn, struct dcesrv_call_state);
 
1123
        if (!call) {
 
1124
                talloc_free(dce_conn->partial_input.data);
 
1125
                return NT_STATUS_NO_MEMORY;
 
1126
        }
 
1127
        call->conn              = dce_conn;
 
1128
        call->event_ctx         = dce_conn->event_ctx;
 
1129
        call->msg_ctx           = dce_conn->msg_ctx;
 
1130
        call->state_flags       = call->conn->state_flags;
 
1131
        call->time              = timeval_current();
 
1132
        call->list              = DCESRV_LIST_NONE;
 
1133
 
 
1134
        talloc_set_destructor(call, dcesrv_call_dequeue);
 
1135
 
 
1136
        blob = dce_conn->partial_input;
 
1137
        blob.length = dcerpc_get_frag_length(&blob);
 
1138
 
 
1139
        ndr = ndr_pull_init_blob(&blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx));
 
1140
        if (!ndr) {
 
1141
                talloc_free(dce_conn->partial_input.data);
 
1142
                talloc_free(call);
 
1143
                return NT_STATUS_NO_MEMORY;
 
1144
        }
 
1145
 
 
1146
        if (!(CVAL(blob.data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
 
1147
                ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
 
1148
        }
 
1149
 
 
1150
        if (CVAL(blob.data, DCERPC_PFC_OFFSET) & DCERPC_PFC_FLAG_OBJECT_UUID) {
 
1151
                ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
 
1152
        }
 
1153
 
 
1154
        ndr_err = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, &call->pkt);
 
1155
        if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
 
1156
                talloc_free(dce_conn->partial_input.data);
 
1157
                talloc_free(call);
 
1158
                return ndr_map_error2ntstatus(ndr_err);
 
1159
        }
 
1160
 
 
1161
        /* we have to check the signing here, before combining the
 
1162
           pdus */
 
1163
        if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
 
1164
            !dcesrv_auth_request(call, &blob)) {
 
1165
                dce_partial_advance(dce_conn, blob.length);
 
1166
                return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);          
 
1167
        }
 
1168
 
 
1169
        dce_partial_advance(dce_conn, blob.length);
 
1170
 
 
1171
        /* see if this is a continued packet */
 
1172
        if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
 
1173
            !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
 
1174
                struct dcesrv_call_state *call2 = call;
 
1175
                uint32_t alloc_size;
 
1176
 
 
1177
                /* we only allow fragmented requests, no other packet types */
 
1178
                if (call->pkt.ptype != DCERPC_PKT_REQUEST) {
 
1179
                        return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
 
1180
                }
 
1181
 
 
1182
                /* this is a continuation of an existing call - find the call then
 
1183
                   tack it on the end */
 
1184
                call = dcesrv_find_fragmented_call(dce_conn, call2->pkt.call_id);
 
1185
                if (!call) {
 
1186
                        return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
 
1187
                }
 
1188
 
 
1189
                if (call->pkt.ptype != call2->pkt.ptype) {
 
1190
                        /* trying to play silly buggers are we? */
 
1191
                        return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
 
1192
                }
 
1193
 
 
1194
                alloc_size = call->pkt.u.request.stub_and_verifier.length +
 
1195
                        call2->pkt.u.request.stub_and_verifier.length;
 
1196
                if (call->pkt.u.request.alloc_hint > alloc_size) {
 
1197
                        alloc_size = call->pkt.u.request.alloc_hint;
 
1198
                }
 
1199
 
 
1200
                call->pkt.u.request.stub_and_verifier.data = 
 
1201
                        talloc_realloc(call, 
 
1202
                                       call->pkt.u.request.stub_and_verifier.data, 
 
1203
                                       uint8_t, alloc_size);
 
1204
                if (!call->pkt.u.request.stub_and_verifier.data) {
 
1205
                        return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
 
1206
                }
 
1207
                memcpy(call->pkt.u.request.stub_and_verifier.data +
 
1208
                       call->pkt.u.request.stub_and_verifier.length,
 
1209
                       call2->pkt.u.request.stub_and_verifier.data,
 
1210
                       call2->pkt.u.request.stub_and_verifier.length);
 
1211
                call->pkt.u.request.stub_and_verifier.length += 
 
1212
                        call2->pkt.u.request.stub_and_verifier.length;
 
1213
 
 
1214
                call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
 
1215
 
 
1216
                talloc_free(call2);
 
1217
        }
 
1218
 
 
1219
        /* this may not be the last pdu in the chain - if its isn't then
 
1220
           just put it on the incoming_fragmented_call_list and wait for the rest */
 
1221
        if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
 
1222
            !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
 
1223
                dcesrv_call_set_list(call, DCESRV_LIST_FRAGMENTED_CALL_LIST);
 
1224
                return NT_STATUS_OK;
 
1225
        } 
 
1226
        
 
1227
        /* This removes any fragments we may have had stashed away */
 
1228
        dcesrv_call_set_list(call, DCESRV_LIST_NONE);
 
1229
 
 
1230
        switch (call->pkt.ptype) {
 
1231
        case DCERPC_PKT_BIND:
 
1232
                status = dcesrv_bind(call);
 
1233
                break;
 
1234
        case DCERPC_PKT_AUTH3:
 
1235
                status = dcesrv_auth3(call);
 
1236
                break;
 
1237
        case DCERPC_PKT_ALTER:
 
1238
                status = dcesrv_alter(call);
 
1239
                break;
 
1240
        case DCERPC_PKT_REQUEST:
 
1241
                status = dcesrv_request(call);
 
1242
                break;
 
1243
        default:
 
1244
                status = NT_STATUS_INVALID_PARAMETER;
 
1245
                break;
 
1246
        }
 
1247
 
 
1248
        /* if we are going to be sending a reply then add
 
1249
           it to the list of pending calls. We add it to the end to keep the call
 
1250
           list in the order we will answer */
 
1251
        if (!NT_STATUS_IS_OK(status)) {
 
1252
                talloc_free(call);
 
1253
        }
 
1254
 
 
1255
        return status;
 
1256
}
 
1257
 
 
1258
 
 
1259
/*
 
1260
  provide some input to a dcerpc endpoint server. This passes data
 
1261
  from a dcerpc client into the server
 
1262
*/
 
1263
_PUBLIC_ NTSTATUS dcesrv_input(struct dcesrv_connection *dce_conn, const DATA_BLOB *data)
 
1264
{
 
1265
        NTSTATUS status;
 
1266
 
 
1267
        dce_conn->partial_input.data = talloc_realloc(dce_conn,
 
1268
                                                      dce_conn->partial_input.data,
 
1269
                                                      uint8_t,
 
1270
                                                      dce_conn->partial_input.length + data->length);
 
1271
        if (!dce_conn->partial_input.data) {
 
1272
                return NT_STATUS_NO_MEMORY;
 
1273
        }
 
1274
        memcpy(dce_conn->partial_input.data + dce_conn->partial_input.length,
 
1275
               data->data, data->length);
 
1276
        dce_conn->partial_input.length += data->length;
 
1277
 
 
1278
        while (dce_full_packet(&dce_conn->partial_input)) {
 
1279
                status = dcesrv_input_process(dce_conn);
 
1280
                if (!NT_STATUS_IS_OK(status)) {
 
1281
                        return status;
 
1282
                }
 
1283
        }
 
1284
 
 
1285
        return NT_STATUS_OK;
 
1286
}
 
1287
 
 
1288
/*
 
1289
  retrieve some output from a dcerpc server
 
1290
  The caller supplies a function that will be called to do the
 
1291
  actual output. 
 
1292
 
 
1293
  The first argument to write_fn() will be 'private', the second will
 
1294
  be a pointer to a buffer containing the data to be sent and the 3rd
 
1295
  will be a pointer to a size_t variable that will be set to the
 
1296
  number of bytes that are consumed from the output.
 
1297
 
 
1298
  from the current fragment
 
1299
*/
 
1300
_PUBLIC_ NTSTATUS dcesrv_output(struct dcesrv_connection *dce_conn, 
 
1301
                       void *private_data,
 
1302
                       NTSTATUS (*write_fn)(void *private_data, DATA_BLOB *output, size_t *nwritten))
 
1303
{
 
1304
        NTSTATUS status;
 
1305
        struct dcesrv_call_state *call;
 
1306
        struct data_blob_list_item *rep;
 
1307
        size_t nwritten;
 
1308
 
 
1309
        call = dce_conn->call_list;
 
1310
        if (!call || !call->replies) {
 
1311
                if (dce_conn->pending_call_list) {
 
1312
                        /* TODO: we need to say act async here
 
1313
                         *       as we know we have pending requests
 
1314
                         *       which will be finished at a time
 
1315
                         */
 
1316
                        return NT_STATUS_FOOBAR;
 
1317
                }
 
1318
                return NT_STATUS_FOOBAR;
 
1319
        }
 
1320
        rep = call->replies;
 
1321
 
 
1322
        status = write_fn(private_data, &rep->blob, &nwritten);
 
1323
        NT_STATUS_IS_ERR_RETURN(status);
 
1324
 
 
1325
        rep->blob.length -= nwritten;
 
1326
        rep->blob.data += nwritten;
 
1327
 
 
1328
        if (rep->blob.length == 0) {
 
1329
                /* we're done with this section of the call */
 
1330
                DLIST_REMOVE(call->replies, rep);
 
1331
        }
 
1332
 
 
1333
        if (call->replies == NULL) {
 
1334
                /* we're done with the whole call */
 
1335
                dcesrv_call_set_list(call, DCESRV_LIST_NONE);
 
1336
                talloc_free(call);
 
1337
        }
 
1338
 
 
1339
        return status;
 
1340
}
 
1341
 
 
1342
_PUBLIC_ NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx, 
 
1343
                                      struct loadparm_context *lp_ctx,
 
1344
                                      const char **endpoint_servers, struct dcesrv_context **_dce_ctx)
 
1345
{
 
1346
        NTSTATUS status;
 
1347
        struct dcesrv_context *dce_ctx;
 
1348
        int i;
 
1349
 
 
1350
        if (!endpoint_servers) {
 
1351
                DEBUG(0,("dcesrv_init_context: no endpoint servers configured\n"));
 
1352
                return NT_STATUS_INTERNAL_ERROR;
 
1353
        }
 
1354
 
 
1355
        dce_ctx = talloc(mem_ctx, struct dcesrv_context);
 
1356
        NT_STATUS_HAVE_NO_MEMORY(dce_ctx);
 
1357
        dce_ctx->endpoint_list  = NULL;
 
1358
        dce_ctx->lp_ctx = lp_ctx;
 
1359
 
 
1360
        for (i=0;endpoint_servers[i];i++) {
 
1361
                const struct dcesrv_endpoint_server *ep_server;
 
1362
 
 
1363
                ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
 
1364
                if (!ep_server) {
 
1365
                        DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
 
1366
                        return NT_STATUS_INTERNAL_ERROR;
 
1367
                }
 
1368
 
 
1369
                status = ep_server->init_server(dce_ctx, ep_server);
 
1370
                if (!NT_STATUS_IS_OK(status)) {
 
1371
                        DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s': %s\n", endpoint_servers[i],
 
1372
                                nt_errstr(status)));
 
1373
                        return status;
 
1374
                }
 
1375
        }
 
1376
 
 
1377
        *_dce_ctx = dce_ctx;
 
1378
        return NT_STATUS_OK;
 
1379
}
 
1380
 
 
1381
/* the list of currently registered DCERPC endpoint servers.
 
1382
 */
 
1383
static struct ep_server {
 
1384
        struct dcesrv_endpoint_server *ep_server;
 
1385
} *ep_servers = NULL;
 
1386
static int num_ep_servers;
 
1387
 
 
1388
/*
 
1389
  register a DCERPC endpoint server. 
 
1390
 
 
1391
  The 'name' can be later used by other backends to find the operations
 
1392
  structure for this backend.  
 
1393
 
 
1394
  The 'type' is used to specify whether this is for a disk, printer or IPC$ share
 
1395
*/
 
1396
_PUBLIC_ NTSTATUS dcerpc_register_ep_server(const void *_ep_server)
 
1397
{
 
1398
        const struct dcesrv_endpoint_server *ep_server = _ep_server;
 
1399
        
 
1400
        if (dcesrv_ep_server_byname(ep_server->name) != NULL) {
 
1401
                /* its already registered! */
 
1402
                DEBUG(0,("DCERPC endpoint server '%s' already registered\n", 
 
1403
                         ep_server->name));
 
1404
                return NT_STATUS_OBJECT_NAME_COLLISION;
 
1405
        }
 
1406
 
 
1407
        ep_servers = realloc_p(ep_servers, struct ep_server, num_ep_servers+1);
 
1408
        if (!ep_servers) {
 
1409
                smb_panic("out of memory in dcerpc_register");
 
1410
        }
 
1411
 
 
1412
        ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server));
 
1413
        ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name);
 
1414
 
 
1415
        num_ep_servers++;
 
1416
 
 
1417
        DEBUG(3,("DCERPC endpoint server '%s' registered\n", 
 
1418
                 ep_server->name));
 
1419
 
 
1420
        return NT_STATUS_OK;
 
1421
}
 
1422
 
 
1423
/*
 
1424
  return the operations structure for a named backend of the specified type
 
1425
*/
 
1426
const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
 
1427
{
 
1428
        int i;
 
1429
 
 
1430
        for (i=0;i<num_ep_servers;i++) {
 
1431
                if (strcmp(ep_servers[i].ep_server->name, name) == 0) {
 
1432
                        return ep_servers[i].ep_server;
 
1433
                }
 
1434
        }
 
1435
 
 
1436
        return NULL;
 
1437
}
 
1438
 
 
1439
void dcerpc_server_init(struct loadparm_context *lp_ctx)
 
1440
{
 
1441
        static bool initialized;
 
1442
        extern NTSTATUS dcerpc_server_wkssvc_init(void);
 
1443
        extern NTSTATUS dcerpc_server_drsuapi_init(void);
 
1444
        extern NTSTATUS dcerpc_server_winreg_init(void);
 
1445
        extern NTSTATUS dcerpc_server_spoolss_init(void);
 
1446
        extern NTSTATUS dcerpc_server_epmapper_init(void);
 
1447
        extern NTSTATUS dcerpc_server_srvsvc_init(void);
 
1448
        extern NTSTATUS dcerpc_server_netlogon_init(void);
 
1449
        extern NTSTATUS dcerpc_server_rpcecho_init(void);
 
1450
        extern NTSTATUS dcerpc_server_unixinfo_init(void);
 
1451
        extern NTSTATUS dcerpc_server_samr_init(void);
 
1452
        extern NTSTATUS dcerpc_server_remote_init(void);
 
1453
        extern NTSTATUS dcerpc_server_lsa_init(void);
 
1454
        extern NTSTATUS dcerpc_server_browser_init(void);
 
1455
        init_module_fn static_init[] = { STATIC_dcerpc_server_MODULES };
 
1456
        init_module_fn *shared_init;
 
1457
 
 
1458
        if (initialized) {
 
1459
                return;
 
1460
        }
 
1461
        initialized = true;
 
1462
 
 
1463
        shared_init = load_samba_modules(NULL, lp_ctx, "dcerpc_server");
 
1464
 
 
1465
        run_init_functions(static_init);
 
1466
        run_init_functions(shared_init);
 
1467
 
 
1468
        talloc_free(shared_init);
 
1469
}
 
1470
 
 
1471
/*
 
1472
  return the DCERPC module version, and the size of some critical types
 
1473
  This can be used by endpoint server modules to either detect compilation errors, or provide
 
1474
  multiple implementations for different smbd compilation options in one module
 
1475
*/
 
1476
const struct dcesrv_critical_sizes *dcerpc_module_version(void)
 
1477
{
 
1478
        static const struct dcesrv_critical_sizes critical_sizes = {
 
1479
                DCERPC_MODULE_VERSION,
 
1480
                sizeof(struct dcesrv_context),
 
1481
                sizeof(struct dcesrv_endpoint),
 
1482
                sizeof(struct dcesrv_endpoint_server),
 
1483
                sizeof(struct dcesrv_interface),
 
1484
                sizeof(struct dcesrv_if_list),
 
1485
                sizeof(struct dcesrv_connection),
 
1486
                sizeof(struct dcesrv_call_state),
 
1487
                sizeof(struct dcesrv_auth),
 
1488
                sizeof(struct dcesrv_handle)
 
1489
        };
 
1490
 
 
1491
        return &critical_sizes;
 
1492
}
 
1493
 
 
1494
/*
 
1495
  initialise the dcerpc server context for ncacn_np based services
 
1496
*/
 
1497
_PUBLIC_ NTSTATUS dcesrv_init_ipc_context(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx,
 
1498
                                          struct dcesrv_context **_dce_ctx)
 
1499
{
 
1500
        NTSTATUS status;
 
1501
        struct dcesrv_context *dce_ctx;
 
1502
 
 
1503
        dcerpc_server_init(lp_ctx);
 
1504
 
 
1505
        status = dcesrv_init_context(mem_ctx, lp_ctx, lp_dcerpc_endpoint_servers(lp_ctx), &dce_ctx);
 
1506
        NT_STATUS_NOT_OK_RETURN(status);
 
1507
 
 
1508
        *_dce_ctx = dce_ctx;
 
1509
        return NT_STATUS_OK;
 
1510
}
 
1511
 
 
1512