336ff878e1842e7fe763de984e54c6bcfacaa310
[idra/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 static NTSTATUS ep_register(TALLOC_CTX *mem_ctx,
295                             struct messaging_context *msg_ctx,
296                             const struct ndr_interface_table *iface,
297                             const struct dcerpc_binding_vector *bind_vec,
298                             const struct GUID *object_guid,
299                             const char *annotation,
300                             uint32_t replace,
301                             uint32_t unregister,
302                             struct dcerpc_binding_handle **pbh)
303 {
304         struct rpc_pipe_client *cli = NULL;
305         struct dcerpc_binding_handle *h;
306         struct pipe_auth_data *auth;
307         const char *ncalrpc_sock;
308         const char *rpcsrv_type;
309         struct epm_entry_t *entries;
310         uint32_t num_ents, i;
311         TALLOC_CTX *tmp_ctx;
312         uint32_t result = EPMAPPER_STATUS_OK;
313         NTSTATUS status;
314
315         if (iface == NULL) {
316                 return NT_STATUS_INVALID_PARAMETER;
317         }
318
319         if (bind_vec == NULL || bind_vec->count == 0) {
320                 return NT_STATUS_INVALID_PARAMETER;
321         }
322
323         tmp_ctx = talloc_stackframe();
324         if (tmp_ctx == NULL) {
325                 return NT_STATUS_NO_MEMORY;
326         }
327
328         rpcsrv_type = lp_parm_const_string(GLOBAL_SECTION_SNUM,
329                                            "rpc_server", "epmapper",
330                                            "none");
331
332         if (strcasecmp_m(rpcsrv_type, "embedded") == 0) {
333                 struct tsocket_address *local;
334                 int rc;
335
336                 rc = tsocket_address_inet_from_strings(tmp_ctx,
337                                                        "ip",
338                                                        "127.0.0.1",
339                                                        0,
340                                                        &local);
341                 if (rc < 0) {
342                         return NT_STATUS_NO_MEMORY;
343                 }
344
345                 status = rpcint_binding_handle(tmp_ctx,
346                                                &ndr_table_epmapper,
347                                                local,
348                                                get_session_info_system(),
349                                                msg_ctx,
350                                                &h);
351                 if (!NT_STATUS_IS_OK(status)) {
352                         DEBUG(1, ("dcerpc_ep_register: Could not connect to "
353                                   "epmapper (%s)", nt_errstr(status)));
354                         goto done;
355                 }
356         } else if (strcasecmp_m(rpcsrv_type, "daemon") == 0) {
357                 /* Connect to the endpoint mapper locally */
358                 ncalrpc_sock = talloc_asprintf(tmp_ctx,
359                                               "%s/%s",
360                                               lp_ncalrpc_dir(),
361                                               "EPMAPPER");
362                 if (ncalrpc_sock == NULL) {
363                         status = NT_STATUS_NO_MEMORY;
364                         goto done;
365                 }
366
367                 status = rpc_pipe_open_ncalrpc(tmp_ctx,
368                                                ncalrpc_sock,
369                                                &ndr_table_epmapper.syntax_id,
370                                                &cli);
371                 if (!NT_STATUS_IS_OK(status)) {
372                         goto done;
373                 }
374
375                 status = rpccli_ncalrpc_bind_data(cli, &auth);
376                 if (!NT_STATUS_IS_OK(status)) {
377                         DEBUG(0, ("Failed to initialize anonymous bind.\n"));
378                         goto done;
379                 }
380
381                 status = rpc_pipe_bind(cli, auth);
382                 if (!NT_STATUS_IS_OK(status)) {
383                         DEBUG(2, ("Failed to bind ncalrpc socket.\n"));
384                         goto done;
385                 }
386
387                 h = cli->binding_handle;
388         } else {
389                 status = NT_STATUS_INVALID_PARAMETER;
390                 goto done;
391         }
392
393         num_ents = bind_vec->count;
394         entries = talloc_array(tmp_ctx, struct epm_entry_t, num_ents);
395
396         for (i = 0; i < num_ents; i++) {
397                 struct dcerpc_binding *map_binding = &bind_vec->bindings[i];
398                 struct epm_twr_t *map_tower;
399
400                 map_tower = talloc_zero(entries, struct epm_twr_t);
401                 if (map_tower == NULL) {
402                         status = NT_STATUS_NO_MEMORY;
403                         goto done;
404                 }
405
406                 status = dcerpc_binding_build_tower(entries,
407                                                     map_binding,
408                                                     &map_tower->tower);
409                 if (!NT_STATUS_IS_OK(status)) {
410                         goto done;
411                 }
412
413                 entries[i].tower = map_tower;
414                 if (annotation == NULL) {
415                         entries[i].annotation = talloc_strdup(entries, "");
416                 } else {
417                         entries[i].annotation = talloc_strndup(entries,
418                                                                annotation,
419                                                                EPM_MAX_ANNOTATION_SIZE);
420                 }
421                 if (entries[i].annotation == NULL) {
422                         status = NT_STATUS_NO_MEMORY;
423                         goto done;
424                 }
425
426                 if (object_guid != NULL) {
427                         entries[i].object = *object_guid;
428                 } else {
429                         entries[i].object = map_binding->object.uuid;
430                 }
431         }
432
433         if (unregister) {
434                 status = dcerpc_epm_Delete(h,
435                                            tmp_ctx,
436                                            num_ents,
437                                            entries,
438                                            &result);
439         } else {
440                 status = dcerpc_epm_Insert(h,
441                                            tmp_ctx,
442                                            num_ents,
443                                            entries,
444                                            replace,
445                                            &result);
446         }
447         if (!NT_STATUS_IS_OK(status)) {
448                 DEBUG(0, ("dcerpc_ep_register: Could not insert tower (%s)\n",
449                           nt_errstr(status)));
450                 goto done;
451         }
452         if (result != EPMAPPER_STATUS_OK) {
453                 DEBUG(0, ("dcerpc_ep_register: Could not insert tower (0x%.8x)\n",
454                           result));
455                 status = NT_STATUS_UNSUCCESSFUL;
456                 goto done;
457         }
458
459         if (pbh != NULL) {
460                 *pbh = talloc_move(mem_ctx, &h);
461                 talloc_steal(*pbh, cli);
462         }
463
464 done:
465         talloc_free(tmp_ctx);
466
467         return status;
468 }
469
470 NTSTATUS dcerpc_ep_register(TALLOC_CTX *mem_ctx,
471                             struct messaging_context *msg_ctx,
472                             const struct ndr_interface_table *iface,
473                             const struct dcerpc_binding_vector *bind_vec,
474                             const struct GUID *object_guid,
475                             const char *annotation,
476                             struct dcerpc_binding_handle **ph)
477 {
478         return ep_register(mem_ctx,
479                            msg_ctx,
480                            iface,
481                            bind_vec,
482                            object_guid,
483                            annotation,
484                            1,
485                            0,
486                            ph);
487 }
488
489 NTSTATUS dcerpc_ep_register_noreplace(TALLOC_CTX *mem_ctx,
490                                       struct messaging_context *msg_ctx,
491                                       const struct ndr_interface_table *iface,
492                                       const struct dcerpc_binding_vector *bind_vec,
493                                       const struct GUID *object_guid,
494                                       const char *annotation,
495                                       struct dcerpc_binding_handle **ph)
496 {
497         return ep_register(mem_ctx,
498                            msg_ctx,
499                            iface,
500                            bind_vec,
501                            object_guid,
502                            annotation,
503                            0,
504                            0,
505                            ph);
506 }
507
508 NTSTATUS dcerpc_ep_unregister(struct messaging_context *msg_ctx,
509                               const struct ndr_interface_table *iface,
510                               const struct dcerpc_binding_vector *bind_vec,
511                               const struct GUID *object_guid)
512 {
513         return ep_register(NULL,
514                            msg_ctx,
515                            iface,
516                            bind_vec,
517                            object_guid,
518                            NULL,
519                            0,
520                            1,
521                            NULL);
522 }
523
524 /* vim: set ts=8 sw=8 noet cindent syntax=c.doxygen: */