s3-librpc: Add dcerpc_binding_vector_replace_iface().
[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 NTSTATUS dcerpc_binding_vector_replace_iface(const struct ndr_interface_table *iface,
247                                              struct dcerpc_binding_vector *v)
248 {
249         uint32_t i;
250
251         for (i = 0; i < v->count; i++) {
252                 struct dcerpc_binding *b;
253
254                 b = &(v->bindings[i]);
255                 b->object = iface->syntax_id;
256         }
257
258         return NT_STATUS_OK;
259 }
260
261 struct dcerpc_binding_vector *dcerpc_binding_vector_dup(TALLOC_CTX *mem_ctx,
262                                                         const struct dcerpc_binding_vector *bvec)
263 {
264         struct dcerpc_binding_vector *v;
265         uint32_t i;
266
267         v = talloc(mem_ctx, struct dcerpc_binding_vector);
268         if (v == NULL) {
269                 return NULL;
270         }
271
272         v->bindings = talloc_array(v, struct dcerpc_binding, bvec->allocated);
273         if (v->bindings == NULL) {
274                 talloc_free(v);
275                 return NULL;
276         }
277         v->allocated = bvec->allocated;
278
279         for (i = 0; i < bvec->count; i++) {
280                 struct dcerpc_binding *b;
281
282                 b = dcerpc_binding_dup(v->bindings, &bvec->bindings[i]);
283                 if (b == NULL) {
284                         talloc_free(v);
285                         return NULL;
286                 }
287                 v->bindings[i] = *b;
288         }
289         v->count = bvec->count;
290
291         return v;
292 }
293
294 NTSTATUS dcerpc_binding_vector_create(TALLOC_CTX *mem_ctx,
295                                       const struct ndr_interface_table *iface,
296                                       uint16_t port,
297                                       const char *ncalrpc,
298                                       struct dcerpc_binding_vector **pbvec)
299 {
300         struct dcerpc_binding_vector *bvec;
301         uint32_t ep_count;
302         uint32_t count = 0;
303         uint32_t i;
304         NTSTATUS status;
305         TALLOC_CTX *tmp_ctx;
306
307         tmp_ctx = talloc_stackframe();
308         if (tmp_ctx == NULL) {
309                 return NT_STATUS_NO_MEMORY;
310         }
311
312         ep_count = iface->endpoints->count;
313
314         bvec = talloc_zero(tmp_ctx, struct dcerpc_binding_vector);
315         if (bvec == NULL) {
316                 status = NT_STATUS_NO_MEMORY;
317                 goto done;
318         }
319
320         bvec->bindings = talloc_zero_array(bvec, struct dcerpc_binding, ep_count);
321         if (bvec->bindings == NULL) {
322                 status = NT_STATUS_NO_MEMORY;
323                 goto done;
324         }
325
326         for (i = 0; i < ep_count; i++) {
327                 struct dcerpc_binding *b;
328
329                 b = talloc_zero(bvec->bindings, struct dcerpc_binding);
330                 if (b == NULL) {
331                         status = NT_STATUS_NO_MEMORY;
332                         goto done;
333                 }
334
335                 status = dcerpc_parse_binding(b, iface->endpoints->names[i], &b);
336                 if (!NT_STATUS_IS_OK(status)) {
337                         status = NT_STATUS_UNSUCCESSFUL;
338                         goto done;
339                 }
340
341                 b->object = iface->syntax_id;
342
343                 switch (b->transport) {
344                         case NCACN_NP:
345                                 b->host = talloc_asprintf(b, "\\\\%s", lp_netbios_name());
346                                 if (b->host == NULL) {
347                                         status = NT_STATUS_NO_MEMORY;
348                                         goto done;
349                                 }
350                                 break;
351                         case NCACN_IP_TCP:
352                                 if (port == 0) {
353                                         talloc_free(b);
354                                         continue;
355                                 }
356
357                                 b->endpoint = talloc_asprintf(b, "%u", port);
358                                 if (b->endpoint == NULL) {
359                                         status = NT_STATUS_NO_MEMORY;
360                                         goto done;
361                                 }
362
363                                 break;
364                         case NCALRPC:
365                                 if (ncalrpc == NULL) {
366                                         talloc_free(b);
367                                         continue;
368                                 }
369
370                                 b->endpoint = talloc_asprintf(b,
371                                                               "%s/%s",
372                                                               lp_ncalrpc_dir(),
373                                                               ncalrpc);
374                                 if (b->endpoint == NULL) {
375                                         status = NT_STATUS_NO_MEMORY;
376                                         goto done;
377                                 }
378                                 break;
379                         default:
380                                 talloc_free(b);
381                                 continue;
382                 }
383
384                 bvec->bindings[count] = *b;
385                 count++;
386         }
387
388         bvec->count = count;
389
390         *pbvec = talloc_move(mem_ctx, &bvec);
391
392         status = NT_STATUS_OK;
393 done:
394         talloc_free(tmp_ctx);
395
396         return status;
397 }
398
399 static NTSTATUS ep_register(TALLOC_CTX *mem_ctx,
400                             struct messaging_context *msg_ctx,
401                             const struct ndr_interface_table *iface,
402                             const struct dcerpc_binding_vector *bind_vec,
403                             const struct GUID *object_guid,
404                             const char *annotation,
405                             uint32_t replace,
406                             uint32_t unregister,
407                             struct dcerpc_binding_handle **pbh)
408 {
409         struct rpc_pipe_client *cli = NULL;
410         struct dcerpc_binding_handle *h;
411         struct pipe_auth_data *auth;
412         const char *ncalrpc_sock;
413         const char *rpcsrv_type;
414         struct epm_entry_t *entries;
415         uint32_t num_ents, i;
416         TALLOC_CTX *tmp_ctx;
417         uint32_t result = EPMAPPER_STATUS_OK;
418         NTSTATUS status;
419
420         if (iface == NULL) {
421                 return NT_STATUS_INVALID_PARAMETER;
422         }
423
424         if (bind_vec == NULL || bind_vec->count == 0) {
425                 return NT_STATUS_INVALID_PARAMETER;
426         }
427
428         tmp_ctx = talloc_stackframe();
429         if (tmp_ctx == NULL) {
430                 return NT_STATUS_NO_MEMORY;
431         }
432
433         rpcsrv_type = lp_parm_const_string(GLOBAL_SECTION_SNUM,
434                                            "rpc_server", "epmapper",
435                                            "none");
436
437         if (strcasecmp_m(rpcsrv_type, "embedded") == 0) {
438                 struct tsocket_address *local;
439                 int rc;
440
441                 rc = tsocket_address_inet_from_strings(tmp_ctx,
442                                                        "ip",
443                                                        "127.0.0.1",
444                                                        0,
445                                                        &local);
446                 if (rc < 0) {
447                         return NT_STATUS_NO_MEMORY;
448                 }
449
450                 status = rpcint_binding_handle(tmp_ctx,
451                                                &ndr_table_epmapper,
452                                                local,
453                                                get_session_info_system(),
454                                                msg_ctx,
455                                                &h);
456                 if (!NT_STATUS_IS_OK(status)) {
457                         DEBUG(1, ("dcerpc_ep_register: Could not connect to "
458                                   "epmapper (%s)", nt_errstr(status)));
459                         goto done;
460                 }
461         } else if (strcasecmp_m(rpcsrv_type, "daemon") == 0) {
462                 /* Connect to the endpoint mapper locally */
463                 ncalrpc_sock = talloc_asprintf(tmp_ctx,
464                                               "%s/%s",
465                                               lp_ncalrpc_dir(),
466                                               "EPMAPPER");
467                 if (ncalrpc_sock == NULL) {
468                         status = NT_STATUS_NO_MEMORY;
469                         goto done;
470                 }
471
472                 status = rpc_pipe_open_ncalrpc(tmp_ctx,
473                                                ncalrpc_sock,
474                                                &ndr_table_epmapper.syntax_id,
475                                                &cli);
476                 if (!NT_STATUS_IS_OK(status)) {
477                         goto done;
478                 }
479
480                 status = rpccli_ncalrpc_bind_data(cli, &auth);
481                 if (!NT_STATUS_IS_OK(status)) {
482                         DEBUG(0, ("Failed to initialize anonymous bind.\n"));
483                         goto done;
484                 }
485
486                 status = rpc_pipe_bind(cli, auth);
487                 if (!NT_STATUS_IS_OK(status)) {
488                         DEBUG(2, ("Failed to bind ncalrpc socket.\n"));
489                         goto done;
490                 }
491
492                 h = cli->binding_handle;
493         } else {
494                 status = NT_STATUS_INVALID_PARAMETER;
495                 goto done;
496         }
497
498         num_ents = bind_vec->count;
499         entries = talloc_array(tmp_ctx, struct epm_entry_t, num_ents);
500
501         for (i = 0; i < num_ents; i++) {
502                 struct dcerpc_binding *map_binding = &bind_vec->bindings[i];
503                 struct epm_twr_t *map_tower;
504
505                 map_tower = talloc_zero(entries, struct epm_twr_t);
506                 if (map_tower == NULL) {
507                         status = NT_STATUS_NO_MEMORY;
508                         goto done;
509                 }
510
511                 status = dcerpc_binding_build_tower(entries,
512                                                     map_binding,
513                                                     &map_tower->tower);
514                 if (!NT_STATUS_IS_OK(status)) {
515                         goto done;
516                 }
517
518                 entries[i].tower = map_tower;
519                 if (annotation == NULL) {
520                         entries[i].annotation = talloc_strdup(entries, "");
521                 } else {
522                         entries[i].annotation = talloc_strndup(entries,
523                                                                annotation,
524                                                                EPM_MAX_ANNOTATION_SIZE);
525                 }
526                 if (entries[i].annotation == NULL) {
527                         status = NT_STATUS_NO_MEMORY;
528                         goto done;
529                 }
530
531                 if (object_guid != NULL) {
532                         entries[i].object = *object_guid;
533                 } else {
534                         entries[i].object = map_binding->object.uuid;
535                 }
536         }
537
538         if (unregister) {
539                 status = dcerpc_epm_Delete(h,
540                                            tmp_ctx,
541                                            num_ents,
542                                            entries,
543                                            &result);
544         } else {
545                 status = dcerpc_epm_Insert(h,
546                                            tmp_ctx,
547                                            num_ents,
548                                            entries,
549                                            replace,
550                                            &result);
551         }
552         if (!NT_STATUS_IS_OK(status)) {
553                 DEBUG(0, ("dcerpc_ep_register: Could not insert tower (%s)\n",
554                           nt_errstr(status)));
555                 goto done;
556         }
557         if (result != EPMAPPER_STATUS_OK) {
558                 DEBUG(0, ("dcerpc_ep_register: Could not insert tower (0x%.8x)\n",
559                           result));
560                 status = NT_STATUS_UNSUCCESSFUL;
561                 goto done;
562         }
563
564         if (pbh != NULL) {
565                 *pbh = talloc_move(mem_ctx, &h);
566                 talloc_steal(*pbh, cli);
567         }
568
569 done:
570         talloc_free(tmp_ctx);
571
572         return status;
573 }
574
575 NTSTATUS dcerpc_ep_register(TALLOC_CTX *mem_ctx,
576                             struct messaging_context *msg_ctx,
577                             const struct ndr_interface_table *iface,
578                             const struct dcerpc_binding_vector *bind_vec,
579                             const struct GUID *object_guid,
580                             const char *annotation,
581                             struct dcerpc_binding_handle **ph)
582 {
583         return ep_register(mem_ctx,
584                            msg_ctx,
585                            iface,
586                            bind_vec,
587                            object_guid,
588                            annotation,
589                            1,
590                            0,
591                            ph);
592 }
593
594 NTSTATUS dcerpc_ep_register_noreplace(TALLOC_CTX *mem_ctx,
595                                       struct messaging_context *msg_ctx,
596                                       const struct ndr_interface_table *iface,
597                                       const struct dcerpc_binding_vector *bind_vec,
598                                       const struct GUID *object_guid,
599                                       const char *annotation,
600                                       struct dcerpc_binding_handle **ph)
601 {
602         return ep_register(mem_ctx,
603                            msg_ctx,
604                            iface,
605                            bind_vec,
606                            object_guid,
607                            annotation,
608                            0,
609                            0,
610                            ph);
611 }
612
613 NTSTATUS dcerpc_ep_unregister(struct messaging_context *msg_ctx,
614                               const struct ndr_interface_table *iface,
615                               const struct dcerpc_binding_vector *bind_vec,
616                               const struct GUID *object_guid)
617 {
618         return ep_register(NULL,
619                            msg_ctx,
620                            iface,
621                            bind_vec,
622                            object_guid,
623                            NULL,
624                            0,
625                            1,
626                            NULL);
627 }
628
629 /* vim: set ts=8 sw=8 noet cindent syntax=c.doxygen: */