~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source4/libnet/libnet_rpc.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
   Copyright (C) Stefan Metzmacher  2004
 
5
   Copyright (C) Rafal Szczesniak   2005
 
6
   
 
7
   This program is free software; you can redistribute it and/or modify
 
8
   it under the terms of the GNU General Public License as published by
 
9
   the Free Software Foundation; either version 3 of the License, or
 
10
   (at your option) any later version.
 
11
   
 
12
   This program is distributed in the hope that it will be useful,
 
13
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
15
   GNU General Public License for more details.
 
16
   
 
17
   You should have received a copy of the GNU General Public License
 
18
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
19
*/
 
20
 
 
21
#include "includes.h"
 
22
#include "libnet/libnet.h"
 
23
#include "libcli/libcli.h"
 
24
#include "libcli/composite/composite.h"
 
25
#include "librpc/rpc/dcerpc.h"
 
26
#include "librpc/rpc/dcerpc_proto.h"
 
27
#include "librpc/gen_ndr/ndr_lsa_c.h"
 
28
#include "librpc/gen_ndr/ndr_samr.h"
 
29
 
 
30
 
 
31
struct rpc_connect_srv_state {
 
32
        struct libnet_context *ctx;
 
33
        struct libnet_RpcConnect r;
 
34
        const char *binding;
 
35
 
 
36
        /* information about the progress */
 
37
        void (*monitor_fn)(struct monitor_msg*);
 
38
};
 
39
 
 
40
 
 
41
static void continue_pipe_connect(struct composite_context *ctx);
 
42
 
 
43
 
 
44
/**
 
45
 * Initiates connection to rpc pipe on remote server
 
46
 * 
 
47
 * @param ctx initialised libnet context
 
48
 * @param mem_ctx memory context of this call
 
49
 * @param r data structure containing necessary parameters and return values
 
50
 * @return composite context of this call
 
51
 **/
 
52
 
 
53
static struct composite_context* libnet_RpcConnectSrv_send(struct libnet_context *ctx,
 
54
                                                           TALLOC_CTX *mem_ctx,
 
55
                                                           struct libnet_RpcConnect *r,
 
56
                                                           void (*monitor)(struct monitor_msg*))
 
57
{
 
58
        struct composite_context *c;    
 
59
        struct rpc_connect_srv_state *s;
 
60
        struct dcerpc_binding *b;
 
61
        struct composite_context *pipe_connect_req;
 
62
 
 
63
        /* composite context allocation and setup */
 
64
        c = composite_create(ctx, ctx->event_ctx);
 
65
        if (c == NULL) return c;
 
66
 
 
67
        s = talloc_zero(c, struct rpc_connect_srv_state);
 
68
        if (composite_nomem(s, c)) return c;
 
69
 
 
70
        c->private_data = s;
 
71
        s->monitor_fn   = monitor;
 
72
 
 
73
        s->ctx = ctx;
 
74
        s->r = *r;
 
75
        ZERO_STRUCT(s->r.out);
 
76
 
 
77
        /* prepare binding string */
 
78
        switch (r->level) {
 
79
        case LIBNET_RPC_CONNECT_SERVER:
 
80
                s->binding = talloc_asprintf(s, "ncacn_np:%s", r->in.name);
 
81
                break;
 
82
        case LIBNET_RPC_CONNECT_SERVER_ADDRESS:
 
83
                s->binding = talloc_asprintf(s, "ncacn_np:%s", r->in.address);
 
84
                break;
 
85
 
 
86
        case LIBNET_RPC_CONNECT_BINDING:
 
87
                s->binding = talloc_strdup(s, r->in.binding);
 
88
                break;
 
89
 
 
90
        case LIBNET_RPC_CONNECT_DC:
 
91
        case LIBNET_RPC_CONNECT_PDC:
 
92
                /* this should never happen - DC and PDC level has a separate
 
93
                   composite function */
 
94
        case LIBNET_RPC_CONNECT_DC_INFO:
 
95
                /* this should never happen - DC_INFO level has a separate
 
96
                   composite function */
 
97
                composite_error(c, NT_STATUS_INVALID_LEVEL);
 
98
                return c;
 
99
        }
 
100
 
 
101
        /* parse binding string to the structure */
 
102
        c->status = dcerpc_parse_binding(c, s->binding, &b);
 
103
        if (!NT_STATUS_IS_OK(c->status)) {
 
104
                DEBUG(0, ("Failed to parse dcerpc binding '%s'\n", s->binding));
 
105
                composite_error(c, c->status);
 
106
                return c;
 
107
        }
 
108
 
 
109
        if (r->level == LIBNET_RPC_CONNECT_SERVER_ADDRESS) {
 
110
                b->target_hostname = talloc_reference(b, r->in.name);
 
111
                if (composite_nomem(b->target_hostname, c)) {
 
112
                        return c;
 
113
                }
 
114
        }
 
115
 
 
116
        /* connect to remote dcerpc pipe */
 
117
        pipe_connect_req = dcerpc_pipe_connect_b_send(c, b, r->in.dcerpc_iface,
 
118
                                                      ctx->cred, c->event_ctx,
 
119
                                                      ctx->lp_ctx);
 
120
        if (composite_nomem(pipe_connect_req, c)) return c;
 
121
 
 
122
        composite_continue(c, pipe_connect_req, continue_pipe_connect, c);
 
123
        return c;
 
124
}
 
125
 
 
126
 
 
127
/*
 
128
  Step 2 of RpcConnectSrv - get rpc connection
 
129
*/
 
130
static void continue_pipe_connect(struct composite_context *ctx)
 
131
{
 
132
        struct composite_context *c;
 
133
        struct rpc_connect_srv_state *s;
 
134
 
 
135
        c = talloc_get_type(ctx->async.private_data, struct composite_context);
 
136
        s = talloc_get_type(c->private_data, struct rpc_connect_srv_state);
 
137
 
 
138
        /* receive result of rpc pipe connection */
 
139
        c->status = dcerpc_pipe_connect_b_recv(ctx, c, &s->r.out.dcerpc_pipe);
 
140
        
 
141
        /* post monitor message */
 
142
        if (s->monitor_fn) {
 
143
                struct monitor_msg msg;
 
144
                struct msg_net_rpc_connect data;
 
145
                struct dcerpc_binding *binding = s->r.out.dcerpc_pipe->binding;
 
146
                
 
147
                /* prepare monitor message and post it */
 
148
                data.host        = binding->host;
 
149
                data.endpoint    = binding->endpoint;
 
150
                data.transport   = binding->transport;
 
151
                data.domain_name = binding->target_hostname;
 
152
                
 
153
                msg.type      = mon_NetRpcConnect;
 
154
                msg.data      = (void*)&data;
 
155
                msg.data_size = sizeof(data);
 
156
                s->monitor_fn(&msg);
 
157
        }
 
158
 
 
159
        composite_done(c);      
 
160
}
 
161
 
 
162
 
 
163
/**
 
164
 * Receives result of connection to rpc pipe on remote server
 
165
 *
 
166
 * @param c composite context
 
167
 * @param ctx initialised libnet context
 
168
 * @param mem_ctx memory context of this call
 
169
 * @param r data structure containing necessary parameters and return values
 
170
 * @return nt status of rpc connection
 
171
 **/
 
172
 
 
173
static NTSTATUS libnet_RpcConnectSrv_recv(struct composite_context *c,
 
174
                                          struct libnet_context *ctx,
 
175
                                          TALLOC_CTX *mem_ctx,
 
176
                                          struct libnet_RpcConnect *r)
 
177
{
 
178
        NTSTATUS status;
 
179
        struct rpc_connect_srv_state *s = talloc_get_type(c->private_data,
 
180
                                          struct rpc_connect_srv_state);
 
181
 
 
182
        status = composite_wait(c);
 
183
        if (NT_STATUS_IS_OK(status)) {
 
184
                /* move the returned rpc pipe between memory contexts */
 
185
                s = talloc_get_type(c->private_data, struct rpc_connect_srv_state);
 
186
                r->out.dcerpc_pipe = talloc_steal(mem_ctx, s->r.out.dcerpc_pipe);
 
187
 
 
188
                /* reference created pipe structure to long-term libnet_context
 
189
                   so that it can be used by other api functions even after short-term
 
190
                   mem_ctx is freed */
 
191
                if (r->in.dcerpc_iface == &ndr_table_samr) {
 
192
                        ctx->samr.pipe = talloc_reference(ctx, r->out.dcerpc_pipe);
 
193
 
 
194
                } else if (r->in.dcerpc_iface == &ndr_table_lsarpc) {
 
195
                        ctx->lsa.pipe = talloc_reference(ctx, r->out.dcerpc_pipe);
 
196
                }
 
197
 
 
198
                r->out.error_string = talloc_strdup(mem_ctx, "Success");
 
199
 
 
200
        } else {
 
201
                r->out.error_string = talloc_asprintf(mem_ctx, "Error: %s", nt_errstr(status));
 
202
        }
 
203
 
 
204
        talloc_free(c);
 
205
        return status;
 
206
}
 
207
 
 
208
 
 
209
struct rpc_connect_dc_state {
 
210
        struct libnet_context *ctx;
 
211
        struct libnet_RpcConnect r;
 
212
        struct libnet_RpcConnect r2;
 
213
        struct libnet_LookupDCs f;
 
214
        const char *connect_name;
 
215
 
 
216
        /* information about the progress */
 
217
        void (*monitor_fn)(struct monitor_msg *);
 
218
};
 
219
 
 
220
 
 
221
static void continue_lookup_dc(struct composite_context *ctx);
 
222
static void continue_rpc_connect(struct composite_context *ctx);
 
223
 
 
224
 
 
225
/**
 
226
 * Initiates connection to rpc pipe on domain pdc
 
227
 * 
 
228
 * @param ctx initialised libnet context
 
229
 * @param mem_ctx memory context of this call
 
230
 * @param r data structure containing necessary parameters and return values
 
231
 * @return composite context of this call
 
232
 **/
 
233
 
 
234
static struct composite_context* libnet_RpcConnectDC_send(struct libnet_context *ctx,
 
235
                                                          TALLOC_CTX *mem_ctx,
 
236
                                                          struct libnet_RpcConnect *r,
 
237
                                                          void (*monitor)(struct monitor_msg *msg))
 
238
{
 
239
        struct composite_context *c;
 
240
        struct rpc_connect_dc_state *s;
 
241
        struct composite_context *lookup_dc_req;
 
242
 
 
243
        /* composite context allocation and setup */
 
244
        c = composite_create(ctx, ctx->event_ctx);
 
245
        if (c == NULL) return c;
 
246
 
 
247
        s = talloc_zero(c, struct rpc_connect_dc_state);
 
248
        if (composite_nomem(s, c)) return c;
 
249
 
 
250
        c->private_data = s;
 
251
        s->monitor_fn   = monitor;
 
252
 
 
253
        s->ctx = ctx;
 
254
        s->r   = *r;
 
255
        ZERO_STRUCT(s->r.out);
 
256
 
 
257
        switch (r->level) {
 
258
        case LIBNET_RPC_CONNECT_PDC:
 
259
                s->f.in.name_type = NBT_NAME_PDC;
 
260
                break;
 
261
 
 
262
        case LIBNET_RPC_CONNECT_DC:
 
263
                s->f.in.name_type = NBT_NAME_LOGON;
 
264
                break;
 
265
 
 
266
        default:
 
267
                break;
 
268
        }
 
269
 
 
270
        s->f.in.domain_name = r->in.name;
 
271
        s->f.out.num_dcs    = 0;
 
272
        s->f.out.dcs        = NULL;
 
273
 
 
274
        /* find the domain pdc first */
 
275
        lookup_dc_req = libnet_LookupDCs_send(ctx, c, &s->f);
 
276
        if (composite_nomem(lookup_dc_req, c)) return c;
 
277
 
 
278
        composite_continue(c, lookup_dc_req, continue_lookup_dc, c);
 
279
        return c;
 
280
}
 
281
 
 
282
 
 
283
/*
 
284
  Step 2 of RpcConnectDC: get domain controller name and
 
285
  initiate RpcConnect to it
 
286
*/
 
287
static void continue_lookup_dc(struct composite_context *ctx)
 
288
{
 
289
        struct composite_context *c;
 
290
        struct rpc_connect_dc_state *s;
 
291
        struct composite_context *rpc_connect_req;
 
292
        struct monitor_msg msg;
 
293
        struct msg_net_lookup_dc data;
 
294
        
 
295
        c = talloc_get_type(ctx->async.private_data, struct composite_context);
 
296
        s = talloc_get_type(c->private_data, struct rpc_connect_dc_state);
 
297
        
 
298
        /* receive result of domain controller lookup */
 
299
        c->status = libnet_LookupDCs_recv(ctx, c, &s->f);
 
300
        if (!composite_is_ok(c)) return;
 
301
 
 
302
        /* decide on preferred address type depending on DC type */
 
303
        s->connect_name = s->f.out.dcs[0].name;
 
304
 
 
305
        /* post monitor message */
 
306
        if (s->monitor_fn) {
 
307
                /* prepare a monitor message and post it */
 
308
                data.domain_name = s->f.in.domain_name;
 
309
                data.hostname    = s->f.out.dcs[0].name;
 
310
                data.address     = s->f.out.dcs[0].address;
 
311
                
 
312
                msg.type         = mon_NetLookupDc;
 
313
                msg.data         = &data;
 
314
                msg.data_size    = sizeof(data);
 
315
                s->monitor_fn(&msg);
 
316
        }
 
317
 
 
318
        /* ok, pdc has been found so do attempt to rpc connect */
 
319
        s->r2.level            = LIBNET_RPC_CONNECT_SERVER_ADDRESS;
 
320
 
 
321
        /* this will cause yet another name resolution, but at least
 
322
         * we pass the right name down the stack now */
 
323
        s->r2.in.name          = talloc_strdup(s, s->connect_name);
 
324
        s->r2.in.address       = talloc_steal(s, s->f.out.dcs[0].address);
 
325
        s->r2.in.dcerpc_iface  = s->r.in.dcerpc_iface;  
 
326
 
 
327
        /* send rpc connect request to the server */
 
328
        rpc_connect_req = libnet_RpcConnectSrv_send(s->ctx, c, &s->r2, s->monitor_fn);
 
329
        if (composite_nomem(rpc_connect_req, c)) return;
 
330
 
 
331
        composite_continue(c, rpc_connect_req, continue_rpc_connect, c);
 
332
}
 
333
 
 
334
 
 
335
/*
 
336
  Step 3 of RpcConnectDC: get rpc connection to the server
 
337
*/
 
338
static void continue_rpc_connect(struct composite_context *ctx)
 
339
{
 
340
        struct composite_context *c;
 
341
        struct rpc_connect_dc_state *s;
 
342
 
 
343
        c = talloc_get_type(ctx->async.private_data, struct composite_context);
 
344
        s = talloc_get_type(c->private_data, struct rpc_connect_dc_state);
 
345
 
 
346
        c->status = libnet_RpcConnectSrv_recv(ctx, s->ctx, c, &s->r2);
 
347
 
 
348
        /* error string is to be passed anyway */
 
349
        s->r.out.error_string  = s->r2.out.error_string;
 
350
        if (!composite_is_ok(c)) return;
 
351
 
 
352
        s->r.out.dcerpc_pipe = s->r2.out.dcerpc_pipe;
 
353
        
 
354
        /* post monitor message */
 
355
        if (s->monitor_fn) {
 
356
                struct monitor_msg msg;
 
357
                struct msg_net_rpc_connect data;
 
358
                struct dcerpc_binding *binding = s->r.out.dcerpc_pipe->binding;
 
359
 
 
360
                data.host        = binding->host;
 
361
                data.endpoint    = binding->endpoint;
 
362
                data.transport   = binding->transport;
 
363
                data.domain_name = binding->target_hostname;
 
364
                
 
365
                msg.type      = mon_NetRpcConnect;
 
366
                msg.data      = (void*)&data;
 
367
                msg.data_size = sizeof(data);
 
368
                s->monitor_fn(&msg);
 
369
        }
 
370
 
 
371
        composite_done(c);
 
372
}
 
373
 
 
374
 
 
375
/**
 
376
 * Receives result of connection to rpc pipe on domain pdc
 
377
 *
 
378
 * @param c composite context
 
379
 * @param ctx initialised libnet context
 
380
 * @param mem_ctx memory context of this call
 
381
 * @param r data structure containing necessary parameters and return values
 
382
 * @return nt status of rpc connection
 
383
 **/
 
384
 
 
385
static NTSTATUS libnet_RpcConnectDC_recv(struct composite_context *c,
 
386
                                         struct libnet_context *ctx,
 
387
                                         TALLOC_CTX *mem_ctx,
 
388
                                         struct libnet_RpcConnect *r)
 
389
{
 
390
        NTSTATUS status;
 
391
        struct rpc_connect_dc_state *s = talloc_get_type(c->private_data,
 
392
                                         struct rpc_connect_dc_state);
 
393
 
 
394
        status = composite_wait(c);
 
395
        if (NT_STATUS_IS_OK(status)) {
 
396
                /* move connected rpc pipe between memory contexts */
 
397
                r->out.dcerpc_pipe = talloc_steal(mem_ctx, s->r.out.dcerpc_pipe);
 
398
 
 
399
                /* reference created pipe structure to long-term libnet_context
 
400
                   so that it can be used by other api functions even after short-term
 
401
                   mem_ctx is freed */
 
402
                if (r->in.dcerpc_iface == &ndr_table_samr) {
 
403
                        ctx->samr.pipe = talloc_reference(ctx, r->out.dcerpc_pipe);
 
404
 
 
405
                } else if (r->in.dcerpc_iface == &ndr_table_lsarpc) {
 
406
                        ctx->lsa.pipe = talloc_reference(ctx, r->out.dcerpc_pipe);
 
407
                }
 
408
 
 
409
        } else {
 
410
                r->out.error_string = talloc_asprintf(mem_ctx,
 
411
                                                      "Failed to rpc connect: %s",
 
412
                                                      nt_errstr(status));
 
413
        }
 
414
 
 
415
        talloc_free(c);
 
416
        return status;
 
417
}
 
418
 
 
419
 
 
420
 
 
421
struct rpc_connect_dci_state {
 
422
        struct libnet_context *ctx;
 
423
        struct libnet_RpcConnect r;
 
424
        struct libnet_RpcConnect rpc_conn;
 
425
        struct policy_handle lsa_handle;
 
426
        struct lsa_QosInfo qos;
 
427
        struct lsa_ObjectAttribute attr;
 
428
        struct lsa_OpenPolicy2 lsa_open_policy;
 
429
        struct dcerpc_pipe *lsa_pipe;
 
430
        struct lsa_QueryInfoPolicy2 lsa_query_info2;
 
431
        struct lsa_QueryInfoPolicy lsa_query_info;
 
432
        struct dcerpc_binding *final_binding;
 
433
        struct dcerpc_pipe *final_pipe;
 
434
 
 
435
        /* information about the progress */
 
436
        void (*monitor_fn)(struct monitor_msg*);
 
437
};
 
438
 
 
439
 
 
440
static void continue_dci_rpc_connect(struct composite_context *ctx);
 
441
static void continue_lsa_policy(struct rpc_request *req);
 
442
static void continue_lsa_query_info(struct rpc_request *req);
 
443
static void continue_lsa_query_info2(struct rpc_request *req);
 
444
static void continue_epm_map_binding(struct composite_context *ctx);
 
445
static void continue_secondary_conn(struct composite_context *ctx);
 
446
static void continue_epm_map_binding_send(struct composite_context *c);
 
447
 
 
448
 
 
449
/**
 
450
 * Initiates connection to rpc pipe on remote server or pdc. Received result
 
451
 * contains info on the domain name, domain sid and realm.
 
452
 * 
 
453
 * @param ctx initialised libnet context
 
454
 * @param mem_ctx memory context of this call
 
455
 * @param r data structure containing necessary parameters and return values. Must be a talloc context
 
456
 * @return composite context of this call
 
457
 **/
 
458
 
 
459
static struct composite_context* libnet_RpcConnectDCInfo_send(struct libnet_context *ctx,
 
460
                                                              TALLOC_CTX *mem_ctx,
 
461
                                                              struct libnet_RpcConnect *r,
 
462
                                                              void (*monitor)(struct monitor_msg*))
 
463
{
 
464
        struct composite_context *c, *conn_req;
 
465
        struct rpc_connect_dci_state *s;
 
466
 
 
467
        /* composite context allocation and setup */
 
468
        c = composite_create(ctx, ctx->event_ctx);
 
469
        if (c == NULL) return c;
 
470
 
 
471
        s = talloc_zero(c, struct rpc_connect_dci_state);
 
472
        if (composite_nomem(s, c)) return c;
 
473
 
 
474
        c->private_data = s;
 
475
        s->monitor_fn   = monitor;
 
476
 
 
477
        s->ctx = ctx;
 
478
        s->r   = *r;
 
479
        ZERO_STRUCT(s->r.out);
 
480
 
 
481
        /* proceed to pure rpc connection if the binding string is provided,
 
482
           otherwise try to connect domain controller */
 
483
        if (r->in.binding == NULL) {
 
484
                s->rpc_conn.in.name    = r->in.name;
 
485
                s->rpc_conn.level      = LIBNET_RPC_CONNECT_DC;
 
486
        } else {
 
487
                s->rpc_conn.in.binding = r->in.binding;
 
488
                s->rpc_conn.level      = LIBNET_RPC_CONNECT_BINDING;
 
489
        }
 
490
 
 
491
        /* we need to query information on lsarpc interface first */
 
492
        s->rpc_conn.in.dcerpc_iface    = &ndr_table_lsarpc;
 
493
        
 
494
        /* request connection to the lsa pipe on the pdc */
 
495
        conn_req = libnet_RpcConnect_send(ctx, c, &s->rpc_conn, s->monitor_fn);
 
496
        if (composite_nomem(c, conn_req)) return c;
 
497
 
 
498
        composite_continue(c, conn_req, continue_dci_rpc_connect, c);
 
499
        return c;
 
500
}
 
501
 
 
502
 
 
503
/*
 
504
  Step 2 of RpcConnectDCInfo: receive opened rpc pipe and open
 
505
  lsa policy handle
 
506
*/
 
507
static void continue_dci_rpc_connect(struct composite_context *ctx)
 
508
{
 
509
        struct composite_context *c;
 
510
        struct rpc_connect_dci_state *s;
 
511
        struct rpc_request *open_pol_req;
 
512
 
 
513
        c = talloc_get_type(ctx->async.private_data, struct composite_context);
 
514
        s = talloc_get_type(c->private_data, struct rpc_connect_dci_state);
 
515
 
 
516
        c->status = libnet_RpcConnect_recv(ctx, s->ctx, c, &s->rpc_conn);
 
517
        if (!NT_STATUS_IS_OK(c->status)) {
 
518
                composite_error(c, c->status);
 
519
                return;
 
520
        }
 
521
 
 
522
        /* post monitor message */
 
523
        if (s->monitor_fn) {
 
524
                struct monitor_msg msg;
 
525
                struct msg_net_rpc_connect data;
 
526
                struct dcerpc_binding *binding = s->r.out.dcerpc_pipe->binding;
 
527
 
 
528
                data.host        = binding->host;
 
529
                data.endpoint    = binding->endpoint;
 
530
                data.transport   = binding->transport;
 
531
                data.domain_name = binding->target_hostname;
 
532
 
 
533
                msg.type      = mon_NetRpcConnect;
 
534
                msg.data      = (void*)&data;
 
535
                msg.data_size = sizeof(data);
 
536
                s->monitor_fn(&msg);
 
537
        }
 
538
 
 
539
        /* prepare to open a policy handle on lsa pipe */
 
540
        s->lsa_pipe = s->ctx->lsa.pipe;
 
541
        
 
542
        s->qos.len                 = 0;
 
543
        s->qos.impersonation_level = 2;
 
544
        s->qos.context_mode        = 1;
 
545
        s->qos.effective_only      = 0;
 
546
 
 
547
        s->attr.sec_qos = &s->qos;
 
548
 
 
549
        s->lsa_open_policy.in.attr        = &s->attr;
 
550
        s->lsa_open_policy.in.system_name = talloc_asprintf(c, "\\");
 
551
        if (composite_nomem(s->lsa_open_policy.in.system_name, c)) return;
 
552
 
 
553
        s->lsa_open_policy.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
 
554
        s->lsa_open_policy.out.handle     = &s->lsa_handle;
 
555
 
 
556
        open_pol_req = dcerpc_lsa_OpenPolicy2_send(s->lsa_pipe, c, &s->lsa_open_policy);
 
557
        if (composite_nomem(open_pol_req, c)) return;
 
558
 
 
559
        composite_continue_rpc(c, open_pol_req, continue_lsa_policy, c);
 
560
}
 
561
 
 
562
 
 
563
/*
 
564
  Step 3 of RpcConnectDCInfo: Get policy handle and query lsa info
 
565
  for kerberos realm (dns name) and guid. The query may fail.
 
566
*/
 
567
static void continue_lsa_policy(struct rpc_request *req)
 
568
{
 
569
        struct composite_context *c;
 
570
        struct rpc_connect_dci_state *s;
 
571
        struct rpc_request *query_info_req;
 
572
 
 
573
        c = talloc_get_type(req->async.private_data, struct composite_context);
 
574
        s = talloc_get_type(c->private_data, struct rpc_connect_dci_state);
 
575
 
 
576
        c->status = dcerpc_ndr_request_recv(req);
 
577
        if (!NT_STATUS_IS_OK(c->status)) {
 
578
                composite_error(c, c->status);
 
579
                return;
 
580
        }
 
581
 
 
582
        if (NT_STATUS_EQUAL(s->lsa_open_policy.out.result, NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED)) {
 
583
                s->r.out.realm = NULL;
 
584
                s->r.out.guid  = NULL;
 
585
                s->r.out.domain_name = NULL;
 
586
                s->r.out.domain_sid  = NULL;
 
587
 
 
588
                /* Skip to the creating the actual connection, no info available on this transport */
 
589
                continue_epm_map_binding_send(c);
 
590
                return;
 
591
 
 
592
        } else if (!NT_STATUS_IS_OK(s->lsa_open_policy.out.result)) {
 
593
                composite_error(c, s->lsa_open_policy.out.result);
 
594
                return;
 
595
        }
 
596
 
 
597
        /* post monitor message */
 
598
        if (s->monitor_fn) {
 
599
                struct monitor_msg msg;
 
600
 
 
601
                msg.type      = mon_LsaOpenPolicy;
 
602
                msg.data      = NULL;
 
603
                msg.data_size = 0;
 
604
                s->monitor_fn(&msg);
 
605
        }
 
606
 
 
607
        /* query lsa info for dns domain name and guid */
 
608
        s->lsa_query_info2.in.handle = &s->lsa_handle;
 
609
        s->lsa_query_info2.in.level  = LSA_POLICY_INFO_DNS;
 
610
        s->lsa_query_info2.out.info  = talloc_zero(c, union lsa_PolicyInformation *);
 
611
        if (composite_nomem(s->lsa_query_info2.out.info, c)) return;
 
612
 
 
613
        query_info_req = dcerpc_lsa_QueryInfoPolicy2_send(s->lsa_pipe, c, &s->lsa_query_info2);
 
614
        if (composite_nomem(query_info_req, c)) return;
 
615
 
 
616
        composite_continue_rpc(c, query_info_req, continue_lsa_query_info2, c);
 
617
}
 
618
 
 
619
 
 
620
/*
 
621
  Step 4 of RpcConnectDCInfo: Get realm and guid if provided (rpc call
 
622
  may result in failure) and query lsa info for domain name and sid.
 
623
*/
 
624
static void continue_lsa_query_info2(struct rpc_request *req)
 
625
{       
 
626
        struct composite_context *c;
 
627
        struct rpc_connect_dci_state *s;
 
628
        struct rpc_request *query_info_req;
 
629
 
 
630
        c = talloc_get_type(req->async.private_data, struct composite_context);
 
631
        s = talloc_get_type(c->private_data, struct rpc_connect_dci_state);
 
632
 
 
633
        c->status = dcerpc_ndr_request_recv(req);
 
634
        
 
635
        /* In case of error just null the realm and guid and proceed
 
636
           to the next step. After all, it doesn't have to be AD domain
 
637
           controller we talking to - NT-style PDC also counts */
 
638
 
 
639
        if (NT_STATUS_EQUAL(c->status, NT_STATUS_NET_WRITE_FAULT)) {
 
640
                s->r.out.realm = NULL;
 
641
                s->r.out.guid  = NULL;
 
642
 
 
643
        } else {
 
644
                if (!NT_STATUS_IS_OK(c->status)) {
 
645
                        s->r.out.error_string = talloc_asprintf(c,
 
646
                                                                "lsa_QueryInfoPolicy2 failed: %s",
 
647
                                                                nt_errstr(c->status));
 
648
                        composite_error(c, c->status);
 
649
                        return;
 
650
                }
 
651
 
 
652
                if (!NT_STATUS_IS_OK(s->lsa_query_info2.out.result)) {
 
653
                        s->r.out.error_string = talloc_asprintf(c,
 
654
                                                                "lsa_QueryInfoPolicy2 failed: %s",
 
655
                                                                nt_errstr(s->lsa_query_info2.out.result));
 
656
                        composite_error(c, s->lsa_query_info2.out.result);
 
657
                        return;
 
658
                }
 
659
 
 
660
                /* Copy the dns domain name and guid from the query result */
 
661
 
 
662
                /* this should actually be a conversion from lsa_StringLarge */
 
663
                s->r.out.realm = (*s->lsa_query_info2.out.info)->dns.dns_domain.string;
 
664
                s->r.out.guid  = talloc(c, struct GUID);
 
665
                if (composite_nomem(s->r.out.guid, c)) {
 
666
                        s->r.out.error_string = NULL;
 
667
                        return;
 
668
                }
 
669
                *s->r.out.guid = (*s->lsa_query_info2.out.info)->dns.domain_guid;
 
670
        }
 
671
 
 
672
        /* post monitor message */
 
673
        if (s->monitor_fn) {
 
674
                struct monitor_msg msg;
 
675
                
 
676
                msg.type      = mon_LsaQueryPolicy;
 
677
                msg.data      = NULL;
 
678
                msg.data_size = 0;
 
679
                s->monitor_fn(&msg);
 
680
        }
 
681
 
 
682
        /* query lsa info for domain name and sid */
 
683
        s->lsa_query_info.in.handle = &s->lsa_handle;
 
684
        s->lsa_query_info.in.level  = LSA_POLICY_INFO_DOMAIN;
 
685
        s->lsa_query_info.out.info  = talloc_zero(c, union lsa_PolicyInformation *);
 
686
        if (composite_nomem(s->lsa_query_info.out.info, c)) return;
 
687
 
 
688
        query_info_req = dcerpc_lsa_QueryInfoPolicy_send(s->lsa_pipe, c, &s->lsa_query_info);
 
689
        if (composite_nomem(query_info_req, c)) return;
 
690
 
 
691
        composite_continue_rpc(c, query_info_req, continue_lsa_query_info, c);
 
692
}
 
693
 
 
694
 
 
695
/*
 
696
  Step 5 of RpcConnectDCInfo: Get domain name and sid
 
697
*/
 
698
static void continue_lsa_query_info(struct rpc_request *req)
 
699
{
 
700
        struct composite_context *c;
 
701
        struct rpc_connect_dci_state *s;
 
702
 
 
703
        c = talloc_get_type(req->async.private_data, struct composite_context);
 
704
        s = talloc_get_type(c->private_data, struct rpc_connect_dci_state);
 
705
 
 
706
        c->status = dcerpc_ndr_request_recv(req);
 
707
        if (!NT_STATUS_IS_OK(c->status)) {
 
708
                s->r.out.error_string = talloc_asprintf(c,
 
709
                                                        "lsa_QueryInfoPolicy failed: %s",
 
710
                                                        nt_errstr(c->status));
 
711
                composite_error(c, c->status);
 
712
                return;
 
713
        }
 
714
 
 
715
        /* post monitor message */
 
716
        if (s->monitor_fn) {
 
717
                struct monitor_msg msg;
 
718
                
 
719
                msg.type      = mon_LsaQueryPolicy;
 
720
                msg.data      = NULL;
 
721
                msg.data_size = 0;
 
722
                s->monitor_fn(&msg);
 
723
        }
 
724
 
 
725
        /* Copy the domain name and sid from the query result */
 
726
        s->r.out.domain_sid  = (*s->lsa_query_info.out.info)->domain.sid;
 
727
        s->r.out.domain_name = (*s->lsa_query_info.out.info)->domain.name.string;
 
728
 
 
729
        continue_epm_map_binding_send(c);
 
730
}
 
731
 
 
732
/* 
 
733
   Step 5 (continued) of RpcConnectDCInfo: request endpoint
 
734
   map binding.
 
735
 
 
736
   We may short-cut to this step if we don't support LSA OpenPolicy on this transport
 
737
*/
 
738
static void continue_epm_map_binding_send(struct composite_context *c)
 
739
{
 
740
        struct rpc_connect_dci_state *s;
 
741
        struct composite_context *epm_map_req;
 
742
        s = talloc_get_type(c->private_data, struct rpc_connect_dci_state);
 
743
 
 
744
        /* prepare to get endpoint mapping for the requested interface */
 
745
        s->final_binding = talloc(s, struct dcerpc_binding);
 
746
        if (composite_nomem(s->final_binding, c)) return;
 
747
        
 
748
        *s->final_binding = *s->lsa_pipe->binding;
 
749
        /* Ensure we keep hold of the member elements */
 
750
        if (composite_nomem(talloc_reference(s->final_binding, s->lsa_pipe->binding), c)) return;
 
751
 
 
752
        epm_map_req = dcerpc_epm_map_binding_send(c, s->final_binding, s->r.in.dcerpc_iface,
 
753
                                                  s->lsa_pipe->conn->event_ctx, s->ctx->lp_ctx);
 
754
        if (composite_nomem(epm_map_req, c)) return;
 
755
 
 
756
        composite_continue(c, epm_map_req, continue_epm_map_binding, c);
 
757
}
 
758
 
 
759
/*
 
760
  Step 6 of RpcConnectDCInfo: Receive endpoint mapping and create secondary
 
761
  rpc connection derived from already used pipe but connected to the requested
 
762
  one (as specified in libnet_RpcConnect structure)
 
763
*/
 
764
static void continue_epm_map_binding(struct composite_context *ctx)
 
765
{
 
766
        struct composite_context *c, *sec_conn_req;
 
767
        struct rpc_connect_dci_state *s;
 
768
 
 
769
        c = talloc_get_type(ctx->async.private_data, struct composite_context);
 
770
        s = talloc_get_type(c->private_data, struct rpc_connect_dci_state);
 
771
 
 
772
        c->status = dcerpc_epm_map_binding_recv(ctx);
 
773
        if (!NT_STATUS_IS_OK(c->status)) {
 
774
                s->r.out.error_string = talloc_asprintf(c,
 
775
                                                        "failed to map pipe with endpoint mapper - %s",
 
776
                                                        nt_errstr(c->status));
 
777
                composite_error(c, c->status);
 
778
                return;
 
779
        }
 
780
 
 
781
        /* create secondary connection derived from lsa pipe */
 
782
        sec_conn_req = dcerpc_secondary_connection_send(s->lsa_pipe, s->final_binding);
 
783
        if (composite_nomem(sec_conn_req, c)) return;
 
784
 
 
785
        composite_continue(c, sec_conn_req, continue_secondary_conn, c);
 
786
}
 
787
 
 
788
 
 
789
/*
 
790
  Step 7 of RpcConnectDCInfo: Get actual pipe to be returned
 
791
  and complete this composite call
 
792
*/
 
793
static void continue_secondary_conn(struct composite_context *ctx)
 
794
{
 
795
        struct composite_context *c;
 
796
        struct rpc_connect_dci_state *s;
 
797
 
 
798
        c = talloc_get_type(ctx->async.private_data, struct composite_context);
 
799
        s = talloc_get_type(c->private_data, struct rpc_connect_dci_state);
 
800
 
 
801
        c->status = dcerpc_secondary_connection_recv(ctx, &s->final_pipe);
 
802
        if (!NT_STATUS_IS_OK(c->status)) {
 
803
                s->r.out.error_string = talloc_asprintf(c,
 
804
                                                        "secondary connection failed: %s",
 
805
                                                        nt_errstr(c->status));
 
806
                
 
807
                composite_error(c, c->status);
 
808
                return;
 
809
        }
 
810
 
 
811
        s->r.out.dcerpc_pipe = s->final_pipe;
 
812
 
 
813
        /* post monitor message */
 
814
        if (s->monitor_fn) {
 
815
                struct monitor_msg msg;
 
816
                struct msg_net_rpc_connect data;
 
817
                struct dcerpc_binding *binding = s->r.out.dcerpc_pipe->binding;
 
818
                
 
819
                /* prepare monitor message and post it */
 
820
                data.host        = binding->host;
 
821
                data.endpoint    = binding->endpoint;
 
822
                data.transport   = binding->transport;
 
823
                data.domain_name = binding->target_hostname;
 
824
                
 
825
                msg.type      = mon_NetRpcConnect;
 
826
                msg.data      = (void*)&data;
 
827
                msg.data_size = sizeof(data);
 
828
                s->monitor_fn(&msg);
 
829
        }
 
830
 
 
831
        composite_done(c);
 
832
}
 
833
 
 
834
 
 
835
/**
 
836
 * Receives result of connection to rpc pipe and gets basic
 
837
 * domain info (name, sid, realm, guid)
 
838
 *
 
839
 * @param c composite context
 
840
 * @param ctx initialised libnet context
 
841
 * @param mem_ctx memory context of this call
 
842
 * @param r data structure containing return values
 
843
 * @return nt status of rpc connection
 
844
 **/
 
845
 
 
846
static NTSTATUS libnet_RpcConnectDCInfo_recv(struct composite_context *c, struct libnet_context *ctx,
 
847
                                             TALLOC_CTX *mem_ctx, struct libnet_RpcConnect *r)
 
848
{
 
849
        NTSTATUS status;
 
850
        struct rpc_connect_dci_state *s = talloc_get_type(c->private_data,
 
851
                                          struct rpc_connect_dci_state);
 
852
 
 
853
        status = composite_wait(c);
 
854
        if (NT_STATUS_IS_OK(status)) {
 
855
                r->out.realm        = talloc_steal(mem_ctx, s->r.out.realm);
 
856
                r->out.guid         = talloc_steal(mem_ctx, s->r.out.guid);
 
857
                r->out.domain_name  = talloc_steal(mem_ctx, s->r.out.domain_name);
 
858
                r->out.domain_sid   = talloc_steal(mem_ctx, s->r.out.domain_sid);
 
859
 
 
860
                r->out.dcerpc_pipe  = talloc_steal(mem_ctx, s->r.out.dcerpc_pipe);
 
861
 
 
862
                /* reference created pipe structure to long-term libnet_context
 
863
                   so that it can be used by other api functions even after short-term
 
864
                   mem_ctx is freed */
 
865
                if (r->in.dcerpc_iface == &ndr_table_samr) {
 
866
                        ctx->samr.pipe = talloc_reference(ctx, r->out.dcerpc_pipe);
 
867
 
 
868
                } else if (r->in.dcerpc_iface == &ndr_table_lsarpc) {
 
869
                        ctx->lsa.pipe = talloc_reference(ctx, r->out.dcerpc_pipe);
 
870
                }
 
871
 
 
872
        } else {
 
873
                if (s->r.out.error_string) {
 
874
                        r->out.error_string = talloc_steal(mem_ctx, s->r.out.error_string);
 
875
                } else if (r->in.binding == NULL) {
 
876
                        r->out.error_string = talloc_asprintf(mem_ctx, "Connection to DC failed: %s", nt_errstr(status));
 
877
                } else {
 
878
                        r->out.error_string = talloc_asprintf(mem_ctx, "Connection to DC %s failed: %s", 
 
879
                                                              r->in.binding, nt_errstr(status));
 
880
                }
 
881
        }
 
882
 
 
883
        talloc_free(c);
 
884
        return status;
 
885
}
 
886
 
 
887
 
 
888
/**
 
889
 * Initiates connection to rpc pipe on remote server or pdc, optionally
 
890
 * providing domain info
 
891
 * 
 
892
 * @param ctx initialised libnet context
 
893
 * @param mem_ctx memory context of this call
 
894
 * @param r data structure containing necessary parameters and return values
 
895
 * @return composite context of this call
 
896
 **/
 
897
 
 
898
struct composite_context* libnet_RpcConnect_send(struct libnet_context *ctx,
 
899
                                                 TALLOC_CTX *mem_ctx,
 
900
                                                 struct libnet_RpcConnect *r,
 
901
                                                 void (*monitor)(struct monitor_msg*))
 
902
{
 
903
        struct composite_context *c;
 
904
 
 
905
        switch (r->level) {
 
906
        case LIBNET_RPC_CONNECT_SERVER:
 
907
        case LIBNET_RPC_CONNECT_SERVER_ADDRESS:
 
908
        case LIBNET_RPC_CONNECT_BINDING:
 
909
                c = libnet_RpcConnectSrv_send(ctx, mem_ctx, r, monitor);
 
910
                break;
 
911
 
 
912
        case LIBNET_RPC_CONNECT_PDC:
 
913
        case LIBNET_RPC_CONNECT_DC:
 
914
                c = libnet_RpcConnectDC_send(ctx, mem_ctx, r, monitor);
 
915
                break;
 
916
 
 
917
        case LIBNET_RPC_CONNECT_DC_INFO:
 
918
                c = libnet_RpcConnectDCInfo_send(ctx, mem_ctx, r, monitor);
 
919
                break;
 
920
 
 
921
        default:
 
922
                c = talloc_zero(mem_ctx, struct composite_context);
 
923
                composite_error(c, NT_STATUS_INVALID_LEVEL);
 
924
        }
 
925
 
 
926
        return c;
 
927
}
 
928
 
 
929
 
 
930
/**
 
931
 * Receives result of connection to rpc pipe on remote server or pdc
 
932
 *
 
933
 * @param c composite context
 
934
 * @param ctx initialised libnet context
 
935
 * @param mem_ctx memory context of this call
 
936
 * @param r data structure containing necessary parameters and return values
 
937
 * @return nt status of rpc connection
 
938
 **/
 
939
 
 
940
NTSTATUS libnet_RpcConnect_recv(struct composite_context *c, struct libnet_context *ctx,
 
941
                                TALLOC_CTX *mem_ctx, struct libnet_RpcConnect *r)
 
942
{
 
943
        switch (r->level) {
 
944
        case LIBNET_RPC_CONNECT_SERVER:
 
945
        case LIBNET_RPC_CONNECT_BINDING:
 
946
                return libnet_RpcConnectSrv_recv(c, ctx, mem_ctx, r);
 
947
 
 
948
        case LIBNET_RPC_CONNECT_PDC:
 
949
        case LIBNET_RPC_CONNECT_DC:
 
950
                return libnet_RpcConnectDC_recv(c, ctx, mem_ctx, r);
 
951
 
 
952
        case LIBNET_RPC_CONNECT_DC_INFO:
 
953
                return libnet_RpcConnectDCInfo_recv(c, ctx, mem_ctx, r);
 
954
 
 
955
        default:
 
956
                ZERO_STRUCT(r->out);
 
957
                return NT_STATUS_INVALID_LEVEL;
 
958
        }
 
959
}
 
960
 
 
961
 
 
962
/**
 
963
 * Connect to a rpc pipe on a remote server - sync version
 
964
 *
 
965
 * @param ctx initialised libnet context
 
966
 * @param mem_ctx memory context of this call
 
967
 * @param r data structure containing necessary parameters and return values
 
968
 * @return nt status of rpc connection
 
969
 **/
 
970
 
 
971
NTSTATUS libnet_RpcConnect(struct libnet_context *ctx, TALLOC_CTX *mem_ctx,
 
972
                           struct libnet_RpcConnect *r)
 
973
{
 
974
        struct composite_context *c;
 
975
        
 
976
        c = libnet_RpcConnect_send(ctx, mem_ctx, r, NULL);
 
977
        return libnet_RpcConnect_recv(c, ctx, mem_ctx, r);
 
978
}