LCOV - code coverage report
Current view: top level - source4/librpc/rpc - dcerpc_util.c (source / functions) Hit Total Coverage
Test: coverage report for vadcx-master-patch-75612 fe003de8 Lines: 293 337 86.9 %
Date: 2024-02-29 22:57:05 Functions: 17 19 89.5 %

          Line data    Source code
       1             : /* 
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    dcerpc utility functions
       5             : 
       6             :    Copyright (C) Andrew Tridgell 2003
       7             :    Copyright (C) Jelmer Vernooij 2004
       8             :    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
       9             :    Copyright (C) Rafal Szczesniak 2006
      10             :    
      11             :    This program is free software; you can redistribute it and/or modify
      12             :    it under the terms of the GNU General Public License as published by
      13             :    the Free Software Foundation; either version 3 of the License, or
      14             :    (at your option) any later version.
      15             :    
      16             :    This program is distributed in the hope that it will be useful,
      17             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      18             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      19             :    GNU General Public License for more details.
      20             :    
      21             :    You should have received a copy of the GNU General Public License
      22             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      23             : */
      24             : 
      25             : #include "includes.h"
      26             : #include "lib/events/events.h"
      27             : #include "libcli/composite/composite.h"
      28             : #include "librpc/gen_ndr/ndr_epmapper_c.h"
      29             : #include "librpc/gen_ndr/ndr_dcerpc.h"
      30             : #include "librpc/gen_ndr/ndr_misc.h"
      31             : #include "librpc/rpc/dcerpc_proto.h"
      32             : #include "auth/credentials/credentials.h"
      33             : #include "auth/gensec/gensec.h"
      34             : #include "param/param.h"
      35             : #include "librpc/rpc/rpc_common.h"
      36             : 
      37             : /*
      38             :   find a dcerpc call on an interface by name
      39             : */
      40           0 : const struct ndr_interface_call *dcerpc_iface_find_call(const struct ndr_interface_table *iface,
      41             :                                                         const char *name)
      42             : {
      43           0 :         uint32_t i;
      44           0 :         for (i=0;i<iface->num_calls;i++) {
      45           0 :                 if (strcmp(iface->calls[i].name, name) == 0) {
      46           0 :                         return &iface->calls[i];
      47             :                 }
      48             :         }
      49           0 :         return NULL;
      50             : }
      51             : 
      52             : struct epm_map_binding_state {
      53             :         struct dcerpc_binding *binding;
      54             :         const struct ndr_interface_table *table;
      55             :         struct dcerpc_pipe *pipe;
      56             :         struct policy_handle handle;
      57             :         struct GUID object;
      58             :         struct epm_twr_t twr;
      59             :         struct epm_twr_t *twr_r;
      60             :         uint32_t num_towers;
      61             :         struct epm_Map r;
      62             : };
      63             : 
      64             : 
      65             : static void continue_epm_recv_binding(struct composite_context *ctx);
      66             : static void continue_epm_map(struct tevent_req *subreq);
      67             : 
      68             : 
      69             : /*
      70             :   Stage 2 of epm_map_binding: Receive connected rpc pipe and send endpoint
      71             :   mapping rpc request
      72             : */
      73       12391 : static void continue_epm_recv_binding(struct composite_context *ctx)
      74             : {
      75       12391 :         struct composite_context *c = talloc_get_type(ctx->async.private_data,
      76             :                                                       struct composite_context);
      77       12391 :         struct epm_map_binding_state *s = talloc_get_type(c->private_data,
      78             :                                                           struct epm_map_binding_state);
      79         125 :         struct tevent_req *subreq;
      80             : 
      81             :         /* receive result of rpc pipe connect request */
      82       12391 :         c->status = dcerpc_pipe_connect_b_recv(ctx, c, &s->pipe);
      83       12391 :         if (!composite_is_ok(c)) return;
      84             : 
      85        6118 :         c->status = dcerpc_binding_build_tower(s->pipe, s->binding, &s->twr.tower);
      86        6118 :         if (!composite_is_ok(c)) return;
      87             :         
      88             :         /* with some nice pretty paper around it of course */
      89        6118 :         s->r.in.object        = &s->object;
      90        6118 :         s->r.in.map_tower     = &s->twr;
      91        6118 :         s->r.in.entry_handle  = &s->handle;
      92        6118 :         s->r.in.max_towers    = 1;
      93        6118 :         s->r.out.entry_handle = &s->handle;
      94        6118 :         s->r.out.num_towers   = &s->num_towers;
      95             : 
      96             :         /* send request for an endpoint mapping - a rpc request on connected pipe */
      97        6243 :         subreq = dcerpc_epm_Map_r_send(s, c->event_ctx,
      98        6118 :                                        s->pipe->binding_handle,
      99             :                                        &s->r);
     100        6118 :         if (composite_nomem(subreq, c)) return;
     101             :         
     102        6118 :         tevent_req_set_callback(subreq, continue_epm_map, c);
     103             : }
     104             : 
     105             : 
     106             : /*
     107             :   Stage 3 of epm_map_binding: Receive endpoint mapping and provide binding details
     108             : */
     109        6118 : static void continue_epm_map(struct tevent_req *subreq)
     110             : {
     111        6118 :         struct composite_context *c = tevent_req_callback_data(subreq,
     112             :                                       struct composite_context);
     113        6118 :         struct epm_map_binding_state *s = talloc_get_type(c->private_data,
     114             :                                                           struct epm_map_binding_state);
     115         125 :         const char *endpoint;
     116             : 
     117             :         /* receive result of a rpc request */
     118        6118 :         c->status = dcerpc_epm_Map_r_recv(subreq, s);
     119        6118 :         TALLOC_FREE(subreq);
     120        6118 :         if (!composite_is_ok(c)) return;
     121             : 
     122             :         /* check the details */
     123        6118 :         if (s->r.out.result != 0 || *s->r.out.num_towers != 1) {
     124          94 :                 composite_error(c, NT_STATUS_PORT_UNREACHABLE);
     125          94 :                 return;
     126             :         }
     127             :         
     128        6024 :         s->twr_r = s->r.out.towers[0].twr;
     129        6024 :         if (s->twr_r == NULL) {
     130           0 :                 composite_error(c, NT_STATUS_PORT_UNREACHABLE);
     131           0 :                 return;
     132             :         }
     133             : 
     134        6024 :         if (s->twr_r->tower.num_floors != s->twr.tower.num_floors ||
     135        6024 :             s->twr_r->tower.floors[3].lhs.protocol != s->twr.tower.floors[3].lhs.protocol) {
     136           0 :                 composite_error(c, NT_STATUS_PORT_UNREACHABLE);
     137           0 :                 return;
     138             :         }
     139             : 
     140             :         /* get received endpoint */
     141        6024 :         endpoint = dcerpc_floor_get_rhs_data(s, &s->twr_r->tower.floors[3]);
     142        6024 :         if (composite_nomem(endpoint, c)) return;
     143             : 
     144        6024 :         c->status = dcerpc_binding_set_string_option(s->binding,
     145             :                                                      "endpoint",
     146             :                                                      endpoint);
     147        6024 :         if (!composite_is_ok(c)) {
     148           0 :                 return;
     149             :         }
     150             : 
     151        6024 :         composite_done(c);
     152             : }
     153             : 
     154             : 
     155             : /*
     156             :   Request for endpoint mapping of dcerpc binding - try to request for endpoint
     157             :   unless there is default one.
     158             : */
     159       31874 : struct composite_context *dcerpc_epm_map_binding_send(TALLOC_CTX *mem_ctx,
     160             :                                                       struct dcerpc_binding *binding,
     161             :                                                       const struct ndr_interface_table *table,
     162             :                                                       struct cli_credentials *creds,
     163             :                                                       struct tevent_context *ev,
     164             :                                                       struct loadparm_context *lp_ctx)
     165             : {
     166         777 :         struct composite_context *c;
     167         777 :         struct epm_map_binding_state *s;
     168         777 :         struct composite_context *pipe_connect_req;
     169         777 :         NTSTATUS status;
     170         777 :         struct dcerpc_binding *epmapper_binding;
     171         777 :         uint32_t i;
     172             : 
     173       31874 :         if (ev == NULL) {
     174           0 :                 return NULL;
     175             :         }
     176             : 
     177             :         /* composite context allocation and setup */
     178       31874 :         c = composite_create(mem_ctx, ev);
     179       31874 :         if (c == NULL) {
     180           0 :                 return NULL;
     181             :         }
     182             : 
     183       31874 :         s = talloc_zero(c, struct epm_map_binding_state);
     184       31874 :         if (composite_nomem(s, c)) return c;
     185       31874 :         c->private_data = s;
     186             : 
     187       31874 :         s->binding = binding;
     188       31874 :         s->object  = dcerpc_binding_get_object(binding);
     189       31874 :         s->table   = table;
     190             : 
     191       31874 :         c->status = dcerpc_binding_set_abstract_syntax(binding,
     192             :                                                        &table->syntax_id);
     193       31874 :         if (!composite_is_ok(c)) {
     194           0 :                 return c;
     195             :         }
     196             : 
     197             :         /*
     198             :           First, check if there is a default endpoint specified in the IDL
     199             :         */
     200       90144 :         for (i = 0; i < table->endpoints->count; i++) {
     201        1282 :                 struct dcerpc_binding *default_binding;
     202        1282 :                 enum dcerpc_transport_t transport;
     203        1282 :                 enum dcerpc_transport_t dtransport;
     204       77752 :                 const char *dendpoint = NULL;
     205             : 
     206       77752 :                 status = dcerpc_parse_binding(s,
     207       77752 :                                               table->endpoints->names[i],
     208             :                                               &default_binding);
     209       77752 :                 if (!NT_STATUS_IS_OK(status)) {
     210       58270 :                         continue;
     211             :                 }
     212             : 
     213       77752 :                 transport = dcerpc_binding_get_transport(binding);
     214       77752 :                 dtransport = dcerpc_binding_get_transport(default_binding);
     215       77752 :                 if (transport == NCA_UNKNOWN) {
     216        1062 :                         c->status = dcerpc_binding_set_transport(binding,
     217             :                                                                  dtransport);
     218        1062 :                         if (!composite_is_ok(c)) {
     219       19482 :                                 return c;
     220             :                         }
     221        1006 :                         transport = dtransport;
     222             :                 }
     223             : 
     224       77752 :                 if (transport != dtransport) {
     225       45936 :                         TALLOC_FREE(default_binding);
     226       45936 :                         continue;
     227             :                 }
     228             : 
     229       31816 :                 dendpoint = dcerpc_binding_get_string_option(default_binding,
     230             :                                                              "endpoint");
     231       31816 :                 if (dendpoint == NULL) {
     232       12334 :                         TALLOC_FREE(default_binding);
     233       12334 :                         continue;
     234             :                 }
     235             : 
     236       19482 :                 c->status = dcerpc_binding_set_string_option(binding,
     237             :                                                              "endpoint",
     238             :                                                              dendpoint);
     239       19482 :                 if (!composite_is_ok(c)) {
     240           0 :                         return c;
     241             :                 }
     242             : 
     243       19482 :                 TALLOC_FREE(default_binding);
     244       19482 :                 composite_done(c);
     245       19482 :                 return c;
     246             :         }
     247             : 
     248       12392 :         epmapper_binding = dcerpc_binding_dup(s, binding);
     249       12392 :         if (composite_nomem(epmapper_binding, c)) return c;
     250             : 
     251             :         /* basic endpoint mapping data */
     252       12392 :         c->status = dcerpc_binding_set_string_option(epmapper_binding,
     253             :                                                      "endpoint", NULL);
     254       12392 :         if (!composite_is_ok(c)) {
     255           0 :                 return c;
     256             :         }
     257       12392 :         c->status = dcerpc_binding_set_flags(epmapper_binding, 0, UINT32_MAX);
     258       12392 :         if (!composite_is_ok(c)) {
     259           0 :                 return c;
     260             :         }
     261       12392 :         c->status = dcerpc_binding_set_assoc_group_id(epmapper_binding, 0);
     262       12392 :         if (!composite_is_ok(c)) {
     263           0 :                 return c;
     264             :         }
     265       12392 :         c->status = dcerpc_binding_set_object(epmapper_binding, GUID_zero());
     266       12392 :         if (!composite_is_ok(c)) {
     267           0 :                 return c;
     268             :         }
     269             : 
     270             :         /* initiate rpc pipe connection */
     271       12392 :         pipe_connect_req = dcerpc_pipe_connect_b_send(s, epmapper_binding,
     272             :                                                       &ndr_table_epmapper,
     273             :                                                       creds, c->event_ctx,
     274             :                                                       lp_ctx);
     275       12392 :         if (composite_nomem(pipe_connect_req, c)) return c;
     276             :         
     277       12392 :         composite_continue(c, pipe_connect_req, continue_epm_recv_binding, c);
     278       12392 :         return c;
     279             : }
     280             : 
     281             : 
     282             : /*
     283             :   Receive result of endpoint mapping request
     284             :  */
     285       31873 : NTSTATUS dcerpc_epm_map_binding_recv(struct composite_context *c)
     286             : {
     287       31873 :         NTSTATUS status = composite_wait(c);
     288             :         
     289       31873 :         talloc_free(c);
     290       31873 :         return status;
     291             : }
     292             : 
     293             : 
     294             : /*
     295             :   Get endpoint mapping for rpc connection
     296             : */
     297        1494 : _PUBLIC_ NTSTATUS dcerpc_epm_map_binding(TALLOC_CTX *mem_ctx, struct dcerpc_binding *binding,
     298             :                                 const struct ndr_interface_table *table, struct tevent_context *ev,
     299             :                                 struct loadparm_context *lp_ctx)
     300             : {
     301         195 :         struct composite_context *c;
     302         195 :         struct cli_credentials *epm_creds;
     303             : 
     304        1494 :         epm_creds = cli_credentials_init_anon(mem_ctx);
     305        1494 :         if (epm_creds == NULL) {
     306           0 :                 return NT_STATUS_NO_MEMORY;
     307             :         }
     308        1494 :         c = dcerpc_epm_map_binding_send(mem_ctx, binding, table, epm_creds, ev, lp_ctx);
     309        1494 :         if (c == NULL) {
     310           0 :                 talloc_free(epm_creds);
     311           0 :                 return NT_STATUS_NO_MEMORY;
     312             :         }
     313        1494 :         talloc_steal(c, epm_creds);
     314        1494 :         return dcerpc_epm_map_binding_recv(c);
     315             : }
     316             : 
     317             : 
     318             : struct pipe_auth_state {
     319             :         struct dcerpc_pipe *pipe;
     320             :         const struct dcerpc_binding *binding;
     321             :         const struct ndr_interface_table *table;
     322             :         struct loadparm_context *lp_ctx;
     323             :         struct cli_credentials *credentials;
     324             :         unsigned int logon_retries;
     325             : };
     326             : 
     327             : 
     328             : static void continue_auth_schannel(struct composite_context *ctx);
     329             : static void continue_auth(struct composite_context *ctx);
     330             : static void continue_auth_none(struct composite_context *ctx);
     331             : static void continue_ntlmssp_connection(struct composite_context *ctx);
     332             : static void continue_spnego_after_wrong_pass(struct composite_context *ctx);
     333             : 
     334             : 
     335             : /*
     336             :   Stage 2 of pipe_auth: Receive result of schannel bind request
     337             : */
     338         469 : static void continue_auth_schannel(struct composite_context *ctx)
     339             : {
     340         469 :         struct composite_context *c = talloc_get_type(ctx->async.private_data,
     341             :                                                       struct composite_context);
     342             : 
     343         469 :         c->status = dcerpc_bind_auth_schannel_recv(ctx);
     344         469 :         if (!composite_is_ok(c)) return;
     345             : 
     346         465 :         composite_done(c);
     347             : }
     348             : 
     349             : 
     350             : /*
     351             :   Stage 2 of pipe_auth: Receive result of authenticated bind request
     352             : */
     353        2650 : static void continue_auth(struct composite_context *ctx)
     354             : {
     355        2650 :         struct composite_context *c = talloc_get_type(ctx->async.private_data,
     356             :                                                       struct composite_context);
     357             : 
     358        2650 :         c->status = dcerpc_bind_auth_recv(ctx);
     359        2650 :         if (!composite_is_ok(c)) return;
     360             :         
     361        2644 :         composite_done(c);
     362             : }
     363             : /*
     364             :   Stage 2 of pipe_auth: Receive result of authenticated bind request, but handle fallbacks:
     365             :   SPNEGO -> NTLMSSP
     366             : */
     367        5556 : static void continue_auth_auto(struct composite_context *ctx)
     368             : {
     369        5556 :         struct composite_context *c = talloc_get_type(ctx->async.private_data,
     370             :                                                       struct composite_context);
     371        5556 :         struct pipe_auth_state *s = talloc_get_type(c->private_data, struct pipe_auth_state);
     372         102 :         struct composite_context *sec_conn_req;
     373             : 
     374        5556 :         c->status = dcerpc_bind_auth_recv(ctx);
     375        5556 :         if (NT_STATUS_EQUAL(c->status, NT_STATUS_INVALID_PARAMETER)) {
     376             :                 /*
     377             :                  * Retry with NTLMSSP auth as fallback
     378             :                  * send a request for secondary rpc connection
     379             :                  */
     380          24 :                 sec_conn_req = dcerpc_secondary_connection_send(s->pipe,
     381             :                                                                 s->binding);
     382          24 :                 composite_continue(c, sec_conn_req, continue_ntlmssp_connection, c);
     383          31 :                 return;
     384        5532 :         } else if (NT_STATUS_EQUAL(c->status, NT_STATUS_LOGON_FAILURE) ||
     385        5430 :                    NT_STATUS_EQUAL(c->status, NT_STATUS_UNSUCCESSFUL)) {
     386             :                 /*
     387             :                   try a second time on any error. We don't just do it
     388             :                   on LOGON_FAILURE as some servers will give a
     389             :                   NT_STATUS_UNSUCCESSFUL on a authentication error on RPC
     390             :                  */
     391           6 :                 const char *principal;
     392           6 :                 const char *endpoint;
     393             : 
     394          25 :                 principal = gensec_get_target_principal(s->pipe->conn->security_state.generic_state);
     395          25 :                 if (principal == NULL) {
     396          25 :                         const char *hostname = gensec_get_target_hostname(s->pipe->conn->security_state.generic_state);
     397          25 :                         const char *service  = gensec_get_target_service(s->pipe->conn->security_state.generic_state);
     398          25 :                         if (hostname != NULL && service != NULL) {
     399          25 :                                 principal = talloc_asprintf(c, "%s/%s", service, hostname);
     400             :                         }
     401             :                 }
     402             : 
     403          25 :                 endpoint = dcerpc_binding_get_string_option(s->binding, "endpoint");
     404             : 
     405          43 :                 if ((cli_credentials_failed_kerberos_login(s->credentials, principal, &s->logon_retries) ||
     406          25 :                      cli_credentials_wrong_password(s->credentials)) &&
     407             :                     endpoint != NULL) {
     408             :                         /*
     409             :                          * Retry SPNEGO with a better password
     410             :                          * send a request for secondary rpc connection
     411             :                          */
     412           7 :                         sec_conn_req = dcerpc_secondary_connection_send(s->pipe,
     413             :                                                                         s->binding);
     414           7 :                         composite_continue(c, sec_conn_req, continue_spnego_after_wrong_pass, c);
     415           7 :                         return;
     416             :                 }
     417             :         }
     418             : 
     419        5525 :         if (!composite_is_ok(c)) return;
     420             : 
     421        5507 :         composite_done(c);
     422             : }
     423             : 
     424             : /*
     425             :   Stage 3 of pipe_auth (fallback to NTLMSSP case): Receive secondary
     426             :   rpc connection (the first one can't be used any more, due to the
     427             :   bind nak) and perform authenticated bind request
     428             : */
     429          24 : static void continue_ntlmssp_connection(struct composite_context *ctx)
     430             : {
     431           0 :         struct composite_context *c;
     432           0 :         struct pipe_auth_state *s;
     433           0 :         struct composite_context *auth_req;
     434           0 :         struct dcerpc_pipe *p2;
     435           0 :         void *pp;
     436             : 
     437          24 :         c = talloc_get_type(ctx->async.private_data, struct composite_context);
     438          24 :         s = talloc_get_type(c->private_data, struct pipe_auth_state);
     439             : 
     440             :         /* receive secondary rpc connection */
     441          24 :         c->status = dcerpc_secondary_connection_recv(ctx, &p2);
     442          24 :         if (!composite_is_ok(c)) return;
     443             : 
     444             : 
     445             :         /* this is a rather strange situation. When
     446             :            we come into the routine, s is a child of s->pipe, and
     447             :            when we created p2 above, it also became a child of
     448             :            s->pipe.
     449             : 
     450             :            Now we want p2 to be a parent of s->pipe, and we want s to
     451             :            be a parent of both of them! If we don't do this very
     452             :            carefully we end up creating a talloc loop
     453             :         */
     454             : 
     455             :         /* we need the new contexts to hang off the same context
     456             :            that s->pipe is on, but the only way to get that is
     457             :            via talloc_parent() */
     458          24 :         pp = talloc_parent(s->pipe);
     459             : 
     460             :         /* promote s to be at the top */
     461          24 :         talloc_steal(pp, s);
     462             : 
     463             :         /* and put p2 under s */
     464          24 :         talloc_steal(s, p2);
     465             : 
     466             :         /* now put s->pipe under p2 */
     467          24 :         talloc_steal(p2, s->pipe);
     468             : 
     469          24 :         s->pipe = p2;
     470             : 
     471             :         /* initiate a authenticated bind */
     472          24 :         auth_req = dcerpc_bind_auth_send(c, s->pipe, s->table,
     473             :                                          s->credentials, 
     474             :                                          lpcfg_gensec_settings(c, s->lp_ctx),
     475             :                                          DCERPC_AUTH_TYPE_NTLMSSP,
     476          24 :                                          dcerpc_auth_level(s->pipe->conn),
     477          24 :                                          s->table->authservices->names[0]);
     478          24 :         composite_continue(c, auth_req, continue_auth, c);
     479             : }
     480             : 
     481             : /*
     482             :   Stage 3 of pipe_auth (retry on wrong password): Receive secondary
     483             :   rpc connection (the first one can't be used any more, due to the
     484             :   bind nak) and perform authenticated bind request
     485             : */
     486           7 : static void continue_spnego_after_wrong_pass(struct composite_context *ctx)
     487             : {
     488           0 :         struct composite_context *c;
     489           0 :         struct pipe_auth_state *s;
     490           0 :         struct composite_context *auth_req;
     491           0 :         struct dcerpc_pipe *p2;
     492             : 
     493           7 :         c = talloc_get_type(ctx->async.private_data, struct composite_context);
     494           7 :         s = talloc_get_type(c->private_data, struct pipe_auth_state);
     495             : 
     496             :         /* receive secondary rpc connection */
     497           7 :         c->status = dcerpc_secondary_connection_recv(ctx, &p2);
     498           7 :         if (!composite_is_ok(c)) return;
     499             : 
     500           7 :         talloc_steal(s, p2);
     501           7 :         talloc_steal(p2, s->pipe);
     502           7 :         s->pipe = p2;
     503             : 
     504             :         /* initiate a authenticated bind */
     505           7 :         auth_req = dcerpc_bind_auth_send(c, s->pipe, s->table,
     506             :                                          s->credentials, 
     507             :                                          lpcfg_gensec_settings(c, s->lp_ctx),
     508             :                                          DCERPC_AUTH_TYPE_SPNEGO,
     509           7 :                                          dcerpc_auth_level(s->pipe->conn),
     510           7 :                                          s->table->authservices->names[0]);
     511           7 :         composite_continue(c, auth_req, continue_auth, c);
     512             : }
     513             : 
     514             : 
     515             : /*
     516             :   Stage 2 of pipe_auth: Receive result of non-authenticated bind request
     517             : */
     518       10639 : static void continue_auth_none(struct composite_context *ctx)
     519             : {
     520       10639 :         struct composite_context *c = talloc_get_type(ctx->async.private_data,
     521             :                                                       struct composite_context);
     522             : 
     523       10639 :         c->status = dcerpc_bind_auth_none_recv(ctx);
     524       10639 :         if (!composite_is_ok(c)) return;
     525             :         
     526       10582 :         composite_done(c);
     527             : }
     528             : 
     529             : 
     530             : /*
     531             :   Request to perform an authenticated bind if required. Authentication
     532             :   is determined using credentials passed and binding flags.
     533             : */
     534       19283 : struct composite_context *dcerpc_pipe_auth_send(struct dcerpc_pipe *p, 
     535             :                                                 const struct dcerpc_binding *binding,
     536             :                                                 const struct ndr_interface_table *table,
     537             :                                                 struct cli_credentials *credentials,
     538             :                                                 struct loadparm_context *lp_ctx)
     539             : {
     540         814 :         struct composite_context *c;
     541         814 :         struct pipe_auth_state *s;
     542         814 :         struct composite_context *auth_schannel_req;
     543         814 :         struct composite_context *auth_req;
     544         814 :         struct composite_context *auth_none_req;
     545         814 :         struct dcecli_connection *conn;
     546         814 :         uint8_t auth_type;
     547             : 
     548             :         /* composite context allocation and setup */
     549       19283 :         c = composite_create(p, p->conn->event_ctx);
     550       19283 :         if (c == NULL) return NULL;
     551             : 
     552       19283 :         s = talloc_zero(c, struct pipe_auth_state);
     553       19283 :         if (composite_nomem(s, c)) return c;
     554       19283 :         c->private_data = s;
     555             : 
     556             :         /* store parameters in state structure */
     557       19283 :         s->binding      = binding;
     558       19283 :         s->table        = table;
     559       19283 :         s->credentials  = credentials;
     560       19283 :         s->pipe         = p;
     561       19283 :         s->lp_ctx       = lp_ctx;
     562             : 
     563       19283 :         conn = s->pipe->conn;
     564       19283 :         conn->flags = dcerpc_binding_get_flags(binding);
     565             : 
     566       19283 :         if (DEBUGLVL(100)) {
     567           0 :                 conn->flags |= DCERPC_DEBUG_PRINT_BOTH;
     568             :         }
     569             : 
     570       19283 :         if (conn->transport.transport == NCALRPC) {
     571        1402 :                 const char *v = dcerpc_binding_get_string_option(binding,
     572             :                                                         "auth_type");
     573             : 
     574        1402 :                 if (v != NULL && strcmp(v, "ncalrpc_as_system") == 0) {
     575         440 :                         auth_req = dcerpc_bind_auth_send(c, s->pipe, s->table,
     576             :                                                  s->credentials,
     577             :                                                  lpcfg_gensec_settings(c, s->lp_ctx),
     578             :                                                  DCERPC_AUTH_TYPE_NCALRPC_AS_SYSTEM,
     579             :                                                  DCERPC_AUTH_LEVEL_CONNECT,
     580         440 :                                                  s->table->authservices->names[0]);
     581         440 :                         composite_continue(c, auth_req, continue_auth, c);
     582         440 :                         return c;
     583             :                 }
     584             :         }
     585             : 
     586       18843 :         if (cli_credentials_is_anonymous(s->credentials)) {
     587        6187 :                 auth_none_req = dcerpc_bind_auth_none_send(c, s->pipe, s->table);
     588        6187 :                 composite_continue(c, auth_none_req, continue_auth_none, c);
     589        6187 :                 return c;
     590             :         }
     591             : 
     592       14931 :         if ((conn->flags & DCERPC_SCHANNEL) &&
     593        2275 :             !cli_credentials_get_netlogon_creds(s->credentials)) {
     594             :                 /* If we don't already have netlogon credentials for
     595             :                  * the schannel bind, then we have to get these
     596             :                  * first */
     597         469 :                 auth_schannel_req = dcerpc_bind_auth_schannel_send(c, s->pipe, s->table,
     598             :                                                                    s->credentials, s->lp_ctx,
     599         469 :                                                                    dcerpc_auth_level(conn));
     600         469 :                 composite_continue(c, auth_schannel_req, continue_auth_schannel, c);
     601         469 :                 return c;
     602             :         }
     603             : 
     604             :         /*
     605             :          * we rely on the already authenticated CIFS connection
     606             :          * if not doing sign or seal
     607             :          */
     608       12187 :         if (conn->transport.transport == NCACN_NP &&
     609        6711 :             !(conn->flags & (DCERPC_PACKET|DCERPC_SIGN|DCERPC_SEAL))) {
     610        4452 :                 auth_none_req = dcerpc_bind_auth_none_send(c, s->pipe, s->table);
     611        4452 :                 composite_continue(c, auth_none_req, continue_auth_none, c);
     612        4452 :                 return c;
     613             :         }
     614             : 
     615             : 
     616             :         /* Perform an authenticated DCE-RPC bind
     617             :          */
     618        7735 :         if (!(conn->flags & (DCERPC_CONNECT|DCERPC_SEAL|DCERPC_PACKET))) {
     619             :                 /*
     620             :                   we are doing an authenticated connection,
     621             :                   which needs to use [connect], [sign] or [seal].
     622             :                   If nothing is specified, we default to [sign] now.
     623             :                   This give roughly the same protection as
     624             :                   ncacn_np with smb signing.
     625             :                 */
     626        2777 :                 conn->flags |= DCERPC_SIGN;
     627             :         }
     628             : 
     629        7735 :         if (conn->flags & DCERPC_AUTH_SPNEGO) {
     630         220 :                 auth_type = DCERPC_AUTH_TYPE_SPNEGO;
     631             : 
     632        7515 :         } else if (conn->flags & DCERPC_AUTH_KRB5) {
     633          93 :                 auth_type = DCERPC_AUTH_TYPE_KRB5;
     634             : 
     635        7422 :         } else if (conn->flags & DCERPC_SCHANNEL) {
     636        1542 :                 auth_type = DCERPC_AUTH_TYPE_SCHANNEL;
     637             : 
     638        5616 :         } else if (conn->flags & DCERPC_AUTH_NTLM) {
     639          60 :                 auth_type = DCERPC_AUTH_TYPE_NTLMSSP;
     640             : 
     641             :         } else {
     642             :                 /* try SPNEGO with fallback to NTLMSSP */
     643        5556 :                 auth_req = dcerpc_bind_auth_send(c, s->pipe, s->table,
     644             :                                                  s->credentials, 
     645             :                                                  lpcfg_gensec_settings(c, s->lp_ctx),
     646             :                                                  DCERPC_AUTH_TYPE_SPNEGO,
     647        5556 :                                                  dcerpc_auth_level(conn),
     648        5556 :                                                  s->table->authservices->names[0]);
     649        5556 :                 composite_continue(c, auth_req, continue_auth_auto, c);
     650        5556 :                 return c;
     651             :         }
     652             : 
     653        2179 :         auth_req = dcerpc_bind_auth_send(c, s->pipe, s->table,
     654             :                                          s->credentials, 
     655             :                                          lpcfg_gensec_settings(c, s->lp_ctx),
     656             :                                          auth_type,
     657        2179 :                                          dcerpc_auth_level(conn),
     658        2179 :                                          s->table->authservices->names[0]);
     659        2179 :         composite_continue(c, auth_req, continue_auth, c);
     660        2179 :         return c;
     661             : }
     662             : 
     663             : 
     664             : /*
     665             :   Receive result of authenticated bind request on dcerpc pipe
     666             : 
     667             :   This returns *p, which may be different to the one originally
     668             :   supplied, as it rebinds to a new pipe due to authentication fallback
     669             : 
     670             : */
     671       19283 : NTSTATUS dcerpc_pipe_auth_recv(struct composite_context *c, TALLOC_CTX *mem_ctx, 
     672             :                                struct dcerpc_pipe **p)
     673             : {
     674         814 :         NTSTATUS status;
     675             : 
     676       19283 :         struct pipe_auth_state *s = talloc_get_type(c->private_data,
     677             :                                                     struct pipe_auth_state);
     678       19283 :         status = composite_wait(c);
     679       19283 :         if (!NT_STATUS_IS_OK(status)) {
     680          85 :                 char *uuid_str = GUID_string(s->pipe, &s->table->syntax_id.uuid);
     681          85 :                 DEBUG(0, ("Failed to bind to uuid %s for %s %s\n", uuid_str,
     682             :                           dcerpc_binding_string(uuid_str, s->binding), nt_errstr(status)));
     683          85 :                 talloc_free(uuid_str);
     684             :         } else {
     685       19198 :                 talloc_steal(mem_ctx, s->pipe);
     686       19198 :                 *p = s->pipe;
     687             :         }
     688             : 
     689       19283 :         talloc_free(c);
     690       19283 :         return status;
     691             : }
     692             : 
     693             : 
     694             : /* 
     695             :    Perform an authenticated bind if needed - sync version
     696             : 
     697             :    This may change *p, as it rebinds to a new pipe due to authentication fallback
     698             : */
     699           0 : _PUBLIC_ NTSTATUS dcerpc_pipe_auth(TALLOC_CTX *mem_ctx,
     700             :                           struct dcerpc_pipe **p, 
     701             :                           const struct dcerpc_binding *binding,
     702             :                           const struct ndr_interface_table *table,
     703             :                           struct cli_credentials *credentials,
     704             :                           struct loadparm_context *lp_ctx)
     705             : {
     706           0 :         struct composite_context *c;
     707             : 
     708           0 :         c = dcerpc_pipe_auth_send(*p, binding, table, credentials, lp_ctx);
     709           0 :         return dcerpc_pipe_auth_recv(c, mem_ctx, p);
     710             : }
     711             : 
     712             : 
     713         768 : NTSTATUS dcecli_generic_session_key(struct dcecli_connection *c,
     714             :                                     DATA_BLOB *session_key)
     715             : {
     716         768 :         if (c != NULL) {
     717         768 :                 if (c->transport.transport != NCALRPC &&
     718         691 :                     c->transport.transport != NCACN_UNIX_STREAM)
     719             :                 {
     720         691 :                         return NT_STATUS_LOCAL_USER_SESSION_KEY;
     721             :                 }
     722             :         }
     723             : 
     724          77 :         return dcerpc_generic_session_key(session_key);
     725             : }
     726             : 
     727             : /*
     728             :   fetch the user session key - may be default (above) or the SMB session key
     729             : 
     730             :   The key is always truncated to 16 bytes 
     731             : */
     732        3998 : _PUBLIC_ NTSTATUS dcerpc_fetch_session_key(struct dcerpc_pipe *p,
     733             :                                            DATA_BLOB *session_key)
     734             : {
     735          72 :         NTSTATUS status;
     736        3998 :         status = p->conn->security_state.session_key(p->conn, session_key);
     737        3998 :         if (!NT_STATUS_IS_OK(status)) {
     738         691 :                 return status;
     739             :         }
     740             : 
     741        3307 :         session_key->length = MIN(session_key->length, 16);
     742             : 
     743        3307 :         return NT_STATUS_OK;
     744             : }
     745             : 
     746          30 : _PUBLIC_ bool dcerpc_transport_encrypted(struct dcerpc_pipe *p)
     747             : {
     748          30 :         if (p == NULL) {
     749           0 :                 return false;
     750             :         }
     751             : 
     752          30 :         if (p->conn == NULL) {
     753           0 :                 return false;
     754             :         }
     755             : 
     756          30 :         return p->conn->transport.encrypted;
     757             : }
     758             : 
     759             : /*
     760             :   create a secondary context from a primary connection
     761             : 
     762             :   this uses dcerpc_alter_context() to create a new dcerpc context_id
     763             : */
     764          33 : _PUBLIC_ NTSTATUS dcerpc_secondary_context(struct dcerpc_pipe *p, 
     765             :                                   struct dcerpc_pipe **pp2,
     766             :                                   const struct ndr_interface_table *table)
     767             : {
     768           6 :         NTSTATUS status;
     769           6 :         struct dcerpc_pipe *p2;
     770          33 :         struct GUID *object = NULL;
     771             :         
     772          33 :         p2 = talloc_zero(p, struct dcerpc_pipe);
     773          33 :         if (p2 == NULL) {
     774           0 :                 return NT_STATUS_NO_MEMORY;
     775             :         }
     776          33 :         p2->conn = talloc_reference(p2, p->conn);
     777          33 :         p2->request_timeout = p->request_timeout;
     778             : 
     779          33 :         p2->context_id = ++p->conn->next_context_id;
     780             : 
     781          33 :         p2->syntax = table->syntax_id;
     782             : 
     783          33 :         p2->transfer_syntax = p->transfer_syntax;
     784             : 
     785          33 :         p2->binding = dcerpc_binding_dup(p2, p->binding);
     786          33 :         if (p2->binding == NULL) {
     787           0 :                 talloc_free(p2);
     788           0 :                 return NT_STATUS_NO_MEMORY;
     789             :         }
     790             : 
     791          33 :         p2->object = dcerpc_binding_get_object(p2->binding);
     792          33 :         if (!GUID_all_zero(&p2->object)) {
     793           0 :                 object = &p2->object;
     794             :         }
     795             : 
     796          33 :         p2->binding_handle = dcerpc_pipe_binding_handle(p2, object, table);
     797          33 :         if (p2->binding_handle == NULL) {
     798           0 :                 talloc_free(p2);
     799           0 :                 return NT_STATUS_NO_MEMORY;
     800             :         }
     801             : 
     802          33 :         status = dcerpc_alter_context(p2, p2, &p2->syntax, &p2->transfer_syntax);
     803          33 :         if (!NT_STATUS_IS_OK(status)) {
     804          15 :                 talloc_free(p2);
     805          15 :                 return status;
     806             :         }
     807             : 
     808          18 :         *pp2 = p2;
     809             : 
     810          18 :         return NT_STATUS_OK;
     811             : }

Generated by: LCOV version 1.14