s3-librpc: Add dcerpc_binding_vector_dup().
[mat/samba.git] / source3 / librpc / rpc / dcerpc_ep.c
1 /*
2  *  Endpoint Mapper Functions
3  *  DCERPC local endpoint mapper client routines
4  *  Copyright (c) 2010-2011 Andreas Schneider.
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 3 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include "includes.h"
21 #include "librpc/rpc/dcerpc.h"
22 #include "librpc/rpc/dcerpc_ep.h"
23 #include "../librpc/gen_ndr/ndr_epmapper_c.h"
24 #include "rpc_client/cli_pipe.h"
25 #include "auth.h"
26 #include "rpc_server/rpc_ncacn_np.h"
27 #include "../lib/tsocket/tsocket.h"
28
29 #define EPM_MAX_ANNOTATION_SIZE 64
30
31 static bool binding_vector_realloc(struct dcerpc_binding_vector *bvec)
32 {
33         if (bvec->count >= bvec->allocated) {
34                 struct dcerpc_binding *tmp;
35
36                 tmp = talloc_realloc(bvec,
37                                      bvec->bindings,
38                                      struct dcerpc_binding,
39                                      bvec->allocated * 2);
40                 if (tmp == NULL) {
41                         return false;
42                 }
43                 bvec->bindings = tmp;
44                 bvec->allocated = bvec->allocated * 2;
45         }
46
47         return true;
48 }
49
50 NTSTATUS dcerpc_binding_vector_new(TALLOC_CTX *mem_ctx,
51                                    struct dcerpc_binding_vector **pbvec)
52 {
53         struct dcerpc_binding_vector *bvec;
54         NTSTATUS status;
55         TALLOC_CTX *tmp_ctx;
56
57         tmp_ctx = talloc_stackframe();
58         if (tmp_ctx == NULL) {
59                 return NT_STATUS_NO_MEMORY;
60         }
61
62         bvec = talloc_zero(tmp_ctx, struct dcerpc_binding_vector);
63         if (bvec == NULL) {
64                 status = NT_STATUS_NO_MEMORY;
65                 goto done;
66         }
67
68         bvec->bindings = talloc_zero_array(bvec,
69                                            struct dcerpc_binding,
70                                            4);
71         if (bvec->bindings == NULL) {
72                 status = NT_STATUS_NO_MEMORY;
73                 goto done;
74         }
75
76         bvec->allocated = 4;
77         bvec->count = 0;
78
79         *pbvec = talloc_move(mem_ctx, &bvec);
80
81         status = NT_STATUS_OK;
82 done:
83         talloc_free(tmp_ctx);
84
85         return status;
86 }
87
88 NTSTATUS dcerpc_binding_vector_add_np_default(const struct ndr_interface_table *iface,
89                                               struct dcerpc_binding_vector *bvec)
90 {
91         uint32_t ep_count = iface->endpoints->count;
92         uint32_t i;
93         NTSTATUS status;
94         bool ok;
95
96         for (i = 0; i < ep_count; i++) {
97                 struct dcerpc_binding *b;
98
99                 b = talloc_zero(bvec->bindings, struct dcerpc_binding);
100                 if (b == NULL) {
101                         return NT_STATUS_NO_MEMORY;
102                 }
103
104                 status = dcerpc_parse_binding(b, iface->endpoints->names[i], &b);
105                 if (!NT_STATUS_IS_OK(status)) {
106                         return NT_STATUS_UNSUCCESSFUL;
107                 }
108
109                 /* Only add the named pipes defined in the iface endpoints */
110                 if (b->transport != NCACN_NP) {
111                         talloc_free(b);
112                         continue;
113                 }
114
115                 b->object = iface->syntax_id;
116
117                 b->host = talloc_asprintf(b, "\\\\%s", lp_netbios_name());
118                 if (b->host == NULL) {
119                         talloc_free(b);
120                         return NT_STATUS_NO_MEMORY;
121                 }
122
123                 ok = binding_vector_realloc(bvec);
124                 if (!ok) {
125                         talloc_free(b);
126                         return NT_STATUS_NO_MEMORY;
127                 }
128
129                 bvec->bindings[bvec->count] = *b;
130                 bvec->count++;
131         }
132
133         return NT_STATUS_OK;
134 }
135
136 NTSTATUS dcerpc_binding_vector_add_port(const struct ndr_interface_table *iface,
137                                         struct dcerpc_binding_vector *bvec,
138                                         const char *host,
139                                         uint16_t port)
140 {
141         uint32_t ep_count = iface->endpoints->count;
142         uint32_t i;
143         NTSTATUS status;
144         bool ok;
145
146         for (i = 0; i < ep_count; i++) {
147                 struct dcerpc_binding *b;
148
149                 b = talloc_zero(bvec->bindings, struct dcerpc_binding);
150                 if (b == NULL) {
151                         return NT_STATUS_NO_MEMORY;
152                 }
153
154                 status = dcerpc_parse_binding(b, iface->endpoints->names[i], &b);
155                 if (!NT_STATUS_IS_OK(status)) {
156                         return NT_STATUS_UNSUCCESSFUL;
157                 }
158
159                 if (b->transport != NCACN_IP_TCP) {
160                         talloc_free(b);
161                         continue;
162                 }
163
164                 b->object = iface->syntax_id;
165
166                 b->host = talloc_strdup(b, host);
167                 if (b->host == NULL) {
168                         talloc_free(b);
169                         return NT_STATUS_NO_MEMORY;
170                 }
171
172                 b->endpoint = talloc_asprintf(b, "%u", port);
173                 if (b->endpoint == NULL) {
174                         talloc_free(b);
175                         return NT_STATUS_NO_MEMORY;
176                 }
177
178                 ok = binding_vector_realloc(bvec);
179                 if (!ok) {
180                         talloc_free(b);
181                         return NT_STATUS_NO_MEMORY;
182                 }
183
184                 bvec->bindings[bvec->count] = *b;
185                 bvec->count++;
186
187                 break;
188         }
189
190         return NT_STATUS_OK;
191 }
192
193 NTSTATUS dcerpc_binding_vector_add_unix(const struct ndr_interface_table *iface,
194                                         struct dcerpc_binding_vector *bvec,
195                                         const char *name)
196 {
197         uint32_t ep_count = iface->endpoints->count;
198         uint32_t i;
199         NTSTATUS status;
200         bool ok;
201
202         for (i = 0; i < ep_count; i++) {
203                 struct dcerpc_binding *b;
204
205                 b = talloc_zero(bvec->bindings, struct dcerpc_binding);
206                 if (b == NULL) {
207                         return NT_STATUS_NO_MEMORY;
208                 }
209
210                 status = dcerpc_parse_binding(b, iface->endpoints->names[i], &b);
211                 if (!NT_STATUS_IS_OK(status)) {
212                         return NT_STATUS_UNSUCCESSFUL;
213                 }
214
215                 if (b->transport != NCALRPC) {
216                         talloc_free(b);
217                         continue;
218                 }
219
220                 b->object = iface->syntax_id;
221
222                 b->endpoint = talloc_asprintf(b,
223                                               "%s/%s",
224                                               lp_ncalrpc_dir(),
225                                               name);
226                 if (b->endpoint == NULL) {
227                         talloc_free(b);
228                         return NT_STATUS_NO_MEMORY;
229                 }
230
231                 ok = binding_vector_realloc(bvec);
232                 if (!ok) {
233                         talloc_free(b);
234                         return NT_STATUS_NO_MEMORY;
235                 }
236
237                 bvec->bindings[bvec->count] = *b;
238                 bvec->count++;
239
240                 break;
241         }
242
243         return NT_STATUS_OK;
244 }
245
246 struct dcerpc_binding_vector *dcerpc_binding_vector_dup(TALLOC_CTX *mem_ctx,
247                                                         const struct dcerpc_binding_vector *bvec)
248 {
249         struct dcerpc_binding_vector *v;
250         uint32_t i;
251
252         v = talloc(mem_ctx, struct dcerpc_binding_vector);
253         if (v == NULL) {
254                 return NULL;
255         }
256
257         v->bindings = talloc_array(v, struct dcerpc_binding, bvec->allocated);
258         if (v->bindings == NULL) {
259                 talloc_free(v);
260                 return NULL;
261         }
262         v->allocated = bvec->allocated;
263
264         for (i = 0; i < bvec->count; i++) {
265                 struct dcerpc_binding *b;
266
267                 b = dcerpc_binding_dup(v->bindings, &bvec->bindings[i]);
268                 if (b == NULL) {
269                         talloc_free(v);
270                         return NULL;
271                 }
272                 v->bindings[i] = *b;
273         }
274         v->count = bvec->count;
275
276         return v;
277 }
278
279 NTSTATUS dcerpc_binding_vector_create(TALLOC_CTX *mem_ctx,
280                                       const struct ndr_interface_table *iface,
281                                       uint16_t port,
282                                       const char *ncalrpc,
283                                       struct dcerpc_binding_vector **pbvec)
284 {
285         struct dcerpc_binding_vector *bvec;
286         uint32_t ep_count;
287         uint32_t count = 0;
288         uint32_t i;
289         NTSTATUS status;
290         TALLOC_CTX *tmp_ctx;
291
292         tmp_ctx = talloc_stackframe();
293         if (tmp_ctx == NULL) {
294                 return NT_STATUS_NO_MEMORY;
295         }
296
297         ep_count = iface->endpoints->count;
298
299         bvec = talloc_zero(tmp_ctx, struct dcerpc_binding_vector);
300         if (bvec == NULL) {
301                 status = NT_STATUS_NO_MEMORY;
302                 goto done;
303         }
304
305         bvec->bindings = talloc_zero_array(bvec, struct dcerpc_binding, ep_count);
306         if (bvec->bindings == NULL) {
307                 status = NT_STATUS_NO_MEMORY;
308                 goto done;
309         }
310
311         for (i = 0; i < ep_count; i++) {
312                 struct dcerpc_binding *b;
313
314                 b = talloc_zero(bvec->bindings, struct dcerpc_binding);
315                 if (b == NULL) {
316                         status = NT_STATUS_NO_MEMORY;
317                         goto done;
318                 }
319
320                 status = dcerpc_parse_binding(b, iface->endpoints->names[i], &b);
321                 if (!NT_STATUS_IS_OK(status)) {
322                         status = NT_STATUS_UNSUCCESSFUL;
323                         goto done;
324                 }
325
326                 b->object = iface->syntax_id;
327
328                 switch (b->transport) {
329                         case NCACN_NP:
330                                 b->host = talloc_asprintf(b, "\\\\%s", lp_netbios_name());
331                                 if (b->host == NULL) {
332                                         status = NT_STATUS_NO_MEMORY;
333                                         goto done;
334                                 }
335                                 break;
336                         case NCACN_IP_TCP:
337                                 if (port == 0) {
338                                         talloc_free(b);
339                                         continue;
340                                 }
341
342                                 b->endpoint = talloc_asprintf(b, "%u", port);
343                                 if (b->endpoint == NULL) {
344                                         status = NT_STATUS_NO_MEMORY;
345                                         goto done;
346                                 }
347
348                                 break;
349                         case NCALRPC:
350                                 if (ncalrpc == NULL) {
351                                         talloc_free(b);
352                                         continue;
353                                 }
354
355                                 b->endpoint = talloc_asprintf(b,
356                                                               "%s/%s",
357                                                               lp_ncalrpc_dir(),
358                                                               ncalrpc);
359                                 if (b->endpoint == NULL) {
360                                         status = NT_STATUS_NO_MEMORY;
361                                         goto done;
362                                 }
363                                 break;
364                         default:
365                                 talloc_free(b);
366                                 continue;
367                 }
368
369                 bvec->bindings[count] = *b;
370                 count++;
371         }
372
373         bvec->count = count;
374
375         *pbvec = talloc_move(mem_ctx, &bvec);
376
377         status = NT_STATUS_OK;
378 done:
379         talloc_free(tmp_ctx);
380
381         return status;
382 }
383
384 static NTSTATUS ep_register(TALLOC_CTX *mem_ctx,
385                             struct messaging_context *msg_ctx,
386                             const struct ndr_interface_table *iface,
387                             const struct dcerpc_binding_vector *bind_vec,
388                             const struct GUID *object_guid,
389                             const char *annotation,
390                             uint32_t replace,
391                             uint32_t unregister,
392                             struct dcerpc_binding_handle **pbh)
393 {
394         struct rpc_pipe_client *cli = NULL;
395         struct dcerpc_binding_handle *h;
396         struct pipe_auth_data *auth;
397         const char *ncalrpc_sock;
398         const char *rpcsrv_type;
399         struct epm_entry_t *entries;
400         uint32_t num_ents, i;
401         TALLOC_CTX *tmp_ctx;
402         uint32_t result = EPMAPPER_STATUS_OK;
403         NTSTATUS status;
404
405         if (iface == NULL) {
406                 return NT_STATUS_INVALID_PARAMETER;
407         }
408
409         if (bind_vec == NULL || bind_vec->count == 0) {
410                 return NT_STATUS_INVALID_PARAMETER;
411         }
412
413         tmp_ctx = talloc_stackframe();
414         if (tmp_ctx == NULL) {
415                 return NT_STATUS_NO_MEMORY;
416         }
417
418         rpcsrv_type = lp_parm_const_string(GLOBAL_SECTION_SNUM,
419                                            "rpc_server", "epmapper",
420                                            "none");
421
422         if (strcasecmp_m(rpcsrv_type, "embedded") == 0) {
423                 struct tsocket_address *local;
424                 int rc;
425
426                 rc = tsocket_address_inet_from_strings(tmp_ctx,
427                                                        "ip",
428                                                        "127.0.0.1",
429                                                        0,
430                                                        &local);
431                 if (rc < 0) {
432                         return NT_STATUS_NO_MEMORY;
433                 }
434
435                 status = rpcint_binding_handle(tmp_ctx,
436                                                &ndr_table_epmapper,
437                                                local,
438                                                get_session_info_system(),
439                                                msg_ctx,
440                                                &h);
441                 if (!NT_STATUS_IS_OK(status)) {
442                         DEBUG(1, ("dcerpc_ep_register: Could not connect to "
443                                   "epmapper (%s)", nt_errstr(status)));
444                         goto done;
445                 }
446         } else if (strcasecmp_m(rpcsrv_type, "daemon") == 0) {
447                 /* Connect to the endpoint mapper locally */
448                 ncalrpc_sock = talloc_asprintf(tmp_ctx,
449                                               "%s/%s",
450                                               lp_ncalrpc_dir(),
451                                               "EPMAPPER");
452                 if (ncalrpc_sock == NULL) {
453                         status = NT_STATUS_NO_MEMORY;
454                         goto done;
455                 }
456
457                 status = rpc_pipe_open_ncalrpc(tmp_ctx,
458                                                ncalrpc_sock,
459                                                &ndr_table_epmapper.syntax_id,
460                                                &cli);
461                 if (!NT_STATUS_IS_OK(status)) {
462                         goto done;
463                 }
464
465                 status = rpccli_ncalrpc_bind_data(cli, &auth);
466                 if (!NT_STATUS_IS_OK(status)) {
467                         DEBUG(0, ("Failed to initialize anonymous bind.\n"));
468                         goto done;
469                 }
470
471                 status = rpc_pipe_bind(cli, auth);
472                 if (!NT_STATUS_IS_OK(status)) {
473                         DEBUG(2, ("Failed to bind ncalrpc socket.\n"));
474                         goto done;
475                 }
476
477                 h = cli->binding_handle;
478         } else {
479                 status = NT_STATUS_INVALID_PARAMETER;
480                 goto done;
481         }
482
483         num_ents = bind_vec->count;
484         entries = talloc_array(tmp_ctx, struct epm_entry_t, num_ents);
485
486         for (i = 0; i < num_ents; i++) {
487                 struct dcerpc_binding *map_binding = &bind_vec->bindings[i];
488                 struct epm_twr_t *map_tower;
489
490                 map_tower = talloc_zero(entries, struct epm_twr_t);
491                 if (map_tower == NULL) {
492                         status = NT_STATUS_NO_MEMORY;
493                         goto done;
494                 }
495
496                 status = dcerpc_binding_build_tower(entries,
497                                                     map_binding,
498                                                     &map_tower->tower);
499                 if (!NT_STATUS_IS_OK(status)) {
500                         goto done;
501                 }
502
503                 entries[i].tower = map_tower;
504                 if (annotation == NULL) {
505                         entries[i].annotation = talloc_strdup(entries, "");
506                 } else {
507                         entries[i].annotation = talloc_strndup(entries,
508                                                                annotation,
509                                                                EPM_MAX_ANNOTATION_SIZE);
510                 }
511                 if (entries[i].annotation == NULL) {
512                         status = NT_STATUS_NO_MEMORY;
513                         goto done;
514                 }
515
516                 if (object_guid != NULL) {
517                         entries[i].object = *object_guid;
518                 } else {
519                         entries[i].object = map_binding->object.uuid;
520                 }
521         }
522
523         if (unregister) {
524                 status = dcerpc_epm_Delete(h,
525                                            tmp_ctx,
526                                            num_ents,
527                                            entries,
528                                            &result);
529         } else {
530                 status = dcerpc_epm_Insert(h,
531                                            tmp_ctx,
532                                            num_ents,
533                                            entries,
534                                            replace,
535                                            &result);
536         }
537         if (!NT_STATUS_IS_OK(status)) {
538                 DEBUG(0, ("dcerpc_ep_register: Could not insert tower (%s)\n",
539                           nt_errstr(status)));
540                 goto done;
541         }
542         if (result != EPMAPPER_STATUS_OK) {
543                 DEBUG(0, ("dcerpc_ep_register: Could not insert tower (0x%.8x)\n",
544                           result));
545                 status = NT_STATUS_UNSUCCESSFUL;
546                 goto done;
547         }
548
549         if (pbh != NULL) {
550                 *pbh = talloc_move(mem_ctx, &h);
551                 talloc_steal(*pbh, cli);
552         }
553
554 done:
555         talloc_free(tmp_ctx);
556
557         return status;
558 }
559
560 NTSTATUS dcerpc_ep_register(TALLOC_CTX *mem_ctx,
561                             struct messaging_context *msg_ctx,
562                             const struct ndr_interface_table *iface,
563                             const struct dcerpc_binding_vector *bind_vec,
564                             const struct GUID *object_guid,
565                             const char *annotation,
566                             struct dcerpc_binding_handle **ph)
567 {
568         return ep_register(mem_ctx,
569                            msg_ctx,
570                            iface,
571                            bind_vec,
572                            object_guid,
573                            annotation,
574                            1,
575                            0,
576                            ph);
577 }
578
579 NTSTATUS dcerpc_ep_register_noreplace(TALLOC_CTX *mem_ctx,
580                                       struct messaging_context *msg_ctx,
581                                       const struct ndr_interface_table *iface,
582                                       const struct dcerpc_binding_vector *bind_vec,
583                                       const struct GUID *object_guid,
584                                       const char *annotation,
585                                       struct dcerpc_binding_handle **ph)
586 {
587         return ep_register(mem_ctx,
588                            msg_ctx,
589                            iface,
590                            bind_vec,
591                            object_guid,
592                            annotation,
593                            0,
594                            0,
595                            ph);
596 }
597
598 NTSTATUS dcerpc_ep_unregister(struct messaging_context *msg_ctx,
599                               const struct ndr_interface_table *iface,
600                               const struct dcerpc_binding_vector *bind_vec,
601                               const struct GUID *object_guid)
602 {
603         return ep_register(NULL,
604                            msg_ctx,
605                            iface,
606                            bind_vec,
607                            object_guid,
608                            NULL,
609                            0,
610                            1,
611                            NULL);
612 }
613
614 /* vim: set ts=8 sw=8 noet cindent syntax=c.doxygen: */