s3:rpc_client: add cli_rpc_pipe_open_schannel_with_creds() helper function
[obnox/samba/samba-obnox.git] / source3 / rpc_client / cli_pipe.c
index cd783f25689b8145216950b3b42918dab859203e..db283060148fedb3d0a90fc5aee4a2fa545050e7 100644 (file)
@@ -1007,8 +1007,7 @@ static NTSTATUS create_generic_auth_rpc_bind_req(struct rpc_pipe_client *cli,
        DATA_BLOB null_blob = data_blob_null;
        NTSTATUS status;
 
-       gensec_security = talloc_get_type_abort(cli->auth->auth_ctx,
-                                       struct gensec_security);
+       gensec_security = cli->auth->auth_ctx;
 
        DEBUG(5, ("create_generic_auth_rpc_bind_req: generate first token\n"));
        status = gensec_update(gensec_security, mem_ctx, null_blob, auth_token);
@@ -1104,10 +1103,10 @@ static NTSTATUS create_rpc_bind_req(TALLOC_CTX *mem_ctx,
        NTSTATUS ret = NT_STATUS_OK;
 
        switch (auth->auth_type) {
-       case DCERPC_AUTH_TYPE_SCHANNEL:
-       case DCERPC_AUTH_TYPE_NTLMSSP:
-       case DCERPC_AUTH_TYPE_KRB5:
-       case DCERPC_AUTH_TYPE_SPNEGO:
+       case DCERPC_AUTH_TYPE_NONE:
+               break;
+
+       default:
                ret = create_generic_auth_rpc_bind_req(cli, mem_ctx,
                                                       &auth_token,
                                                       &auth->client_hdr_signing);
@@ -1117,19 +1116,6 @@ static NTSTATUS create_rpc_bind_req(TALLOC_CTX *mem_ctx,
                        return ret;
                }
                break;
-
-       case DCERPC_AUTH_TYPE_NCALRPC_AS_SYSTEM:
-               auth_token = data_blob_talloc(mem_ctx,
-                                             "NCALRPC_AUTH_TOKEN",
-                                             18);
-               break;
-
-       case DCERPC_AUTH_TYPE_NONE:
-               break;
-
-       default:
-               /* "Can't" happen. */
-               return NT_STATUS_INVALID_INFO_CLASS;
        }
 
        if (auth_token.length != 0) {
@@ -1836,15 +1822,11 @@ static void rpc_pipe_bind_step_one_done(struct tevent_req *subreq)
        switch(pauth->auth_type) {
 
        case DCERPC_AUTH_TYPE_NONE:
-       case DCERPC_AUTH_TYPE_NCALRPC_AS_SYSTEM:
                /* Bind complete. */
                tevent_req_done(req);
                return;
 
-       case DCERPC_AUTH_TYPE_SCHANNEL:
-       case DCERPC_AUTH_TYPE_NTLMSSP:
-       case DCERPC_AUTH_TYPE_SPNEGO:
-       case DCERPC_AUTH_TYPE_KRB5:
+       default:
                /* Paranoid lenght checks */
                if (pkt->frag_length < DCERPC_AUTH_TRAILER_LENGTH
                                                + pkt->auth_length) {
@@ -1863,9 +1845,6 @@ static void rpc_pipe_bind_step_one_done(struct tevent_req *subreq)
                        return;
                }
                break;
-
-       default:
-               goto err_out;
        }
 
        /*
@@ -1875,17 +1854,12 @@ static void rpc_pipe_bind_step_one_done(struct tevent_req *subreq)
        switch(pauth->auth_type) {
 
        case DCERPC_AUTH_TYPE_NONE:
-       case DCERPC_AUTH_TYPE_NCALRPC_AS_SYSTEM:
                /* Bind complete. */
                tevent_req_done(req);
                return;
 
-       case DCERPC_AUTH_TYPE_SCHANNEL:
-       case DCERPC_AUTH_TYPE_NTLMSSP:
-       case DCERPC_AUTH_TYPE_KRB5:
-       case DCERPC_AUTH_TYPE_SPNEGO:
-               gensec_security = talloc_get_type_abort(pauth->auth_ctx,
-                                               struct gensec_security);
+       default:
+               gensec_security = pauth->auth_ctx;
 
                if (pkt->pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN) {
                        if (pauth->client_hdr_signing) {
@@ -1911,20 +1885,12 @@ static void rpc_pipe_bind_step_one_done(struct tevent_req *subreq)
                                                        &auth_token);
                }
                break;
-
-       default:
-               goto err_out;
        }
 
        if (!NT_STATUS_IS_OK(status)) {
                tevent_req_nterror(req, status);
        }
        return;
-
-err_out:
-       DEBUG(0,("cli_finish_bind_auth: unknown auth type %u\n",
-                (unsigned int)state->cli->auth->auth_type));
-       tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
 }
 
 static NTSTATUS rpc_bind_next_send(struct tevent_req *req,
@@ -2317,50 +2283,53 @@ struct dcerpc_binding_handle *rpccli_bh_create(struct rpc_pipe_client *c,
        return h;
 }
 
-NTSTATUS rpccli_ncalrpc_bind_data(TALLOC_CTX *mem_ctx,
-                                 struct pipe_auth_data **presult)
+NTSTATUS rpccli_anon_bind_data(TALLOC_CTX *mem_ctx,
+                              struct pipe_auth_data **presult)
 {
        struct pipe_auth_data *result;
+       struct auth_generic_state *auth_generic_ctx;
+       NTSTATUS status;
 
        result = talloc_zero(mem_ctx, struct pipe_auth_data);
        if (result == NULL) {
                return NT_STATUS_NO_MEMORY;
        }
 
-       result->auth_type = DCERPC_AUTH_TYPE_NCALRPC_AS_SYSTEM;
-       result->auth_level = DCERPC_AUTH_LEVEL_CONNECT;
+       result->auth_type = DCERPC_AUTH_TYPE_NONE;
+       result->auth_level = DCERPC_AUTH_LEVEL_NONE;
 
-       result->user_name = talloc_strdup(result, "");
-       result->domain = talloc_strdup(result, "");
-       if ((result->user_name == NULL) || (result->domain == NULL)) {
-               TALLOC_FREE(result);
-               return NT_STATUS_NO_MEMORY;
+       status = auth_generic_client_prepare(result,
+                                            &auth_generic_ctx);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(1, ("Failed to create auth_generic context: %s\n",
+                         nt_errstr(status)));
        }
 
-       *presult = result;
-       return NT_STATUS_OK;
-}
-
-NTSTATUS rpccli_anon_bind_data(TALLOC_CTX *mem_ctx,
-                              struct pipe_auth_data **presult)
-{
-       struct pipe_auth_data *result;
-
-       result = talloc_zero(mem_ctx, struct pipe_auth_data);
-       if (result == NULL) {
-               return NT_STATUS_NO_MEMORY;
+       status = auth_generic_set_username(auth_generic_ctx, "");
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(1, ("Failed to set username: %s\n",
+                         nt_errstr(status)));
        }
 
-       result->auth_type = DCERPC_AUTH_TYPE_NONE;
-       result->auth_level = DCERPC_AUTH_LEVEL_NONE;
+       status = auth_generic_set_domain(auth_generic_ctx, "");
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(1, ("Failed to set domain: %s\n",
+                         nt_errstr(status)));
+               return status;
+       }
 
-       result->user_name = talloc_strdup(result, "");
-       result->domain = talloc_strdup(result, "");
-       if ((result->user_name == NULL) || (result->domain == NULL)) {
-               TALLOC_FREE(result);
-               return NT_STATUS_NO_MEMORY;
+       status = gensec_set_credentials(auth_generic_ctx->gensec_security,
+                                       auth_generic_ctx->credentials);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(1, ("Failed to set GENSEC credentials: %s\n",
+                         nt_errstr(status)));
+               return status;
        }
+       talloc_unlink(auth_generic_ctx, auth_generic_ctx->credentials);
+       auth_generic_ctx->credentials = NULL;
 
+       result->auth_ctx = talloc_move(result, &auth_generic_ctx->gensec_security);
+       talloc_free(auth_generic_ctx);
        *presult = result;
        return NT_STATUS_OK;
 }
@@ -2389,13 +2358,6 @@ static NTSTATUS rpccli_generic_bind_data(TALLOC_CTX *mem_ctx,
        result->auth_type = auth_type;
        result->auth_level = auth_level;
 
-       result->user_name = talloc_strdup(result, username);
-       result->domain = talloc_strdup(result, domain);
-       if ((result->user_name == NULL) || (result->domain == NULL)) {
-               status = NT_STATUS_NO_MEMORY;
-               goto fail;
-       }
-
        status = auth_generic_client_prepare(result,
                                             &auth_generic_ctx);
        if (!NT_STATUS_IS_OK(status)) {
@@ -2445,6 +2407,79 @@ static NTSTATUS rpccli_generic_bind_data(TALLOC_CTX *mem_ctx,
        return status;
 }
 
+/* This routine steals the creds pointer that is passed in */
+static NTSTATUS rpccli_generic_bind_data_from_creds(TALLOC_CTX *mem_ctx,
+                                                   enum dcerpc_AuthType auth_type,
+                                                   enum dcerpc_AuthLevel auth_level,
+                                                   const char *server,
+                                                   const char *target_service,
+                                                   struct cli_credentials *creds,
+                                                   struct pipe_auth_data **presult)
+{
+       struct auth_generic_state *auth_generic_ctx;
+       struct pipe_auth_data *result;
+       NTSTATUS status;
+
+       result = talloc_zero(mem_ctx, struct pipe_auth_data);
+       if (result == NULL) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       result->auth_type = auth_type;
+       result->auth_level = auth_level;
+
+       status = auth_generic_client_prepare(result,
+                                            &auth_generic_ctx);
+       if (!NT_STATUS_IS_OK(status)) {
+               goto fail;
+       }
+
+       status = auth_generic_set_creds(auth_generic_ctx, creds);
+       if (!NT_STATUS_IS_OK(status)) {
+               goto fail;
+       }
+
+       status = gensec_set_target_service(auth_generic_ctx->gensec_security, target_service);
+       if (!NT_STATUS_IS_OK(status)) {
+               goto fail;
+       }
+
+       status = gensec_set_target_hostname(auth_generic_ctx->gensec_security, server);
+       if (!NT_STATUS_IS_OK(status)) {
+               goto fail;
+       }
+
+       status = auth_generic_client_start_by_authtype(auth_generic_ctx, auth_type, auth_level);
+       if (!NT_STATUS_IS_OK(status)) {
+               goto fail;
+       }
+
+       result->auth_ctx = talloc_move(result, &auth_generic_ctx->gensec_security);
+       talloc_free(auth_generic_ctx);
+       *presult = result;
+       return NT_STATUS_OK;
+
+ fail:
+       TALLOC_FREE(result);
+       return status;
+}
+
+NTSTATUS rpccli_ncalrpc_bind_data(TALLOC_CTX *mem_ctx,
+                                 struct pipe_auth_data **presult)
+{
+       return rpccli_generic_bind_data(mem_ctx,
+                                       DCERPC_AUTH_TYPE_NCALRPC_AS_SYSTEM,
+                                       DCERPC_AUTH_LEVEL_CONNECT,
+                                       NULL, /* server */
+                                       "host", /* target_service */
+                                       NAME_NT_AUTHORITY, /* domain */
+                                       "SYSTEM",
+                                       "", /* password */
+                                       CRED_DONT_USE_KERBEROS,
+                                       NULL, /* netlogon_creds_CredentialState */
+                                       presult);
+}
+
 /**
  * Create an rpc pipe client struct, connecting to a tcp port.
  */
@@ -2907,12 +2942,6 @@ NTSTATUS cli_rpc_pipe_open_noauth_transport(struct cli_state *cli,
         * from the enclosing SMB creds
         */
 
-       TALLOC_FREE(auth->user_name);
-       TALLOC_FREE(auth->domain);
-
-       auth->user_name = talloc_strdup(auth, cli->user_name);
-       auth->domain = talloc_strdup(auth, cli->domain);
-
        if (transport == NCACN_NP) {
                struct smbXcli_session *session;
 
@@ -2929,11 +2958,6 @@ NTSTATUS cli_rpc_pipe_open_noauth_transport(struct cli_state *cli,
                }
        }
 
-       if ((auth->user_name == NULL) || (auth->domain == NULL)) {
-               TALLOC_FREE(result);
-               return NT_STATUS_NO_MEMORY;
-       }
-
        status = rpc_pipe_bind(result, auth);
        if (!NT_STATUS_IS_OK(status)) {
                int lvl = 0;
@@ -2973,11 +2997,71 @@ NTSTATUS cli_rpc_pipe_open_noauth(struct cli_state *cli,
 
 /****************************************************************************
  Open a named pipe to an SMB server and bind using the mech specified
+
+ This routine references the creds pointer that is passed in
+ ****************************************************************************/
+
+NTSTATUS cli_rpc_pipe_open_with_creds(struct cli_state *cli,
+                                     const struct ndr_interface_table *table,
+                                     enum dcerpc_transport_t transport,
+                                     enum dcerpc_AuthType auth_type,
+                                     enum dcerpc_AuthLevel auth_level,
+                                     const char *server,
+                                     struct cli_credentials *creds,
+                                     struct rpc_pipe_client **presult)
+{
+       struct rpc_pipe_client *result;
+       struct pipe_auth_data *auth = NULL;
+       const char *target_service = table->authservices->names[0];
+
+       NTSTATUS status;
+
+       status = cli_rpc_pipe_open(cli, transport, table, &result);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
+       status = rpccli_generic_bind_data_from_creds(result,
+                                                    auth_type, auth_level,
+                                                    server, target_service,
+                                                    creds,
+                                                    &auth);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(0, ("rpccli_generic_bind_data returned %s\n",
+                         nt_errstr(status)));
+               goto err;
+       }
+
+       status = rpc_pipe_bind(result, auth);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(0, ("cli_rpc_pipe_open_generic_auth: cli_rpc_pipe_bind failed with error %s\n",
+                       nt_errstr(status) ));
+               goto err;
+       }
+
+       DEBUG(10,("cli_rpc_pipe_open_generic_auth: opened pipe %s to "
+               "machine %s and bound as user %s.\n", table->name,
+                 result->desthost, cli_credentials_get_unparsed_name(creds, talloc_tos())));
+
+       *presult = result;
+       return NT_STATUS_OK;
+
+  err:
+
+       TALLOC_FREE(result);
+       return status;
+}
+
+/****************************************************************************
+ Open a named pipe to an SMB server and bind using the mech specified
+
+ This routine steals the creds pointer that is passed in
  ****************************************************************************/
 
 NTSTATUS cli_rpc_pipe_open_generic_auth(struct cli_state *cli,
                                        const struct ndr_interface_table *table,
                                        enum dcerpc_transport_t transport,
+                                       enum credentials_use_kerberos use_kerberos,
                                        enum dcerpc_AuthType auth_type,
                                        enum dcerpc_AuthLevel auth_level,
                                        const char *server,
@@ -3126,67 +3210,90 @@ done:
        return NT_STATUS_OK;
 }
 
-NTSTATUS cli_rpc_pipe_open_spnego(struct cli_state *cli,
-                                 const struct ndr_interface_table *table,
-                                 enum dcerpc_transport_t transport,
-                                 const char *oid,
-                                 enum dcerpc_AuthLevel auth_level,
-                                 const char *server,
-                                 const char *domain,
-                                 const char *username,
-                                 const char *password,
-                                 struct rpc_pipe_client **presult)
+NTSTATUS cli_rpc_pipe_open_schannel_with_creds(struct cli_state *cli,
+                                              const struct ndr_interface_table *table,
+                                              enum dcerpc_transport_t transport,
+                                              struct cli_credentials *cli_creds,
+                                              struct netlogon_creds_cli_context *netlogon_creds,
+                                              struct rpc_pipe_client **_rpccli)
 {
-       struct rpc_pipe_client *result;
-       struct pipe_auth_data *auth = NULL;
+       struct rpc_pipe_client *rpccli;
+       struct pipe_auth_data *rpcauth;
        const char *target_service = table->authservices->names[0];
-       
+       struct netlogon_creds_CredentialState *ncreds = NULL;
+       enum dcerpc_AuthLevel auth_level;
        NTSTATUS status;
-       enum credentials_use_kerberos use_kerberos;
+       int rpc_pipe_bind_dbglvl = 0;
 
-       if (strcmp(oid, GENSEC_OID_KERBEROS5) == 0) {
-               use_kerberos = CRED_MUST_USE_KERBEROS;
-       } else if (strcmp(oid, GENSEC_OID_NTLMSSP) == 0) {
-               use_kerberos = CRED_DONT_USE_KERBEROS;
-       } else {
-               return NT_STATUS_INVALID_PARAMETER;
+       status = cli_rpc_pipe_open(cli, transport, table, &rpccli);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
        }
 
-       status = cli_rpc_pipe_open(cli, transport, table, &result);
+       status = netlogon_creds_cli_lock(netlogon_creds, rpccli, &ncreds);
        if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(0, ("netlogon_creds_cli_get returned %s\n",
+                         nt_errstr(status)));
+               TALLOC_FREE(rpccli);
                return status;
        }
 
-       status = rpccli_generic_bind_data(result,
-                                         DCERPC_AUTH_TYPE_SPNEGO, auth_level,
-                                         server, target_service,
-                                         domain, username, password, 
-                                         use_kerberos, NULL,
-                                         &auth);
+       auth_level = netlogon_creds_cli_auth_level(netlogon_creds);
+
+       cli_credentials_set_netlogon_creds(cli_creds, ncreds);
+
+       status = rpccli_generic_bind_data_from_creds(rpccli,
+                                                    DCERPC_AUTH_TYPE_SCHANNEL,
+                                                    auth_level,
+                                                    rpccli->desthost,
+                                                    target_service,
+                                                    cli_creds,
+                                                    &rpcauth);
        if (!NT_STATUS_IS_OK(status)) {
-               DEBUG(0, ("rpccli_generic_bind_data returned %s\n",
+               DEBUG(0, ("rpccli_generic_bind_data_from_creds returned %s\n",
                          nt_errstr(status)));
-               goto err;
+               TALLOC_FREE(rpccli);
+               return status;
        }
 
-       status = rpc_pipe_bind(result, auth);
+       status = rpc_pipe_bind(rpccli, rpcauth);
+       cli_credentials_set_netlogon_creds(cli_creds, NULL);
+       if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED)) {
+               rpc_pipe_bind_dbglvl = 1;
+               netlogon_creds_cli_delete(netlogon_creds, &ncreds);
+       }
        if (!NT_STATUS_IS_OK(status)) {
-               DEBUG(0, ("cli_rpc_pipe_open_spnego: cli_rpc_pipe_bind failed with error %s\n",
-                       nt_errstr(status) ));
-               goto err;
+               DEBUG(rpc_pipe_bind_dbglvl,
+                     ("%s: rpc_pipe_bind failed with error %s\n",
+                      __func__, nt_errstr(status)));
+               TALLOC_FREE(rpccli);
+               return status;
        }
 
-       DEBUG(10,("cli_rpc_pipe_open_spnego: opened pipe %s to "
-                 "machine %s.\n", table->name,
-                 result->desthost));
+       TALLOC_FREE(ncreds);
 
-       *presult = result;
-       return NT_STATUS_OK;
+       if (!ndr_syntax_id_equal(&table->syntax_id, &ndr_table_netlogon.syntax_id)) {
+               goto done;
+       }
 
-  err:
+       status = netlogon_creds_cli_check(netlogon_creds,
+                                         rpccli->binding_handle);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(0, ("netlogon_creds_cli_check failed with %s\n",
+                         nt_errstr(status)));
+               TALLOC_FREE(rpccli);
+               return status;
+       }
 
-       TALLOC_FREE(result);
-       return status;
+
+done:
+       DEBUG(10,("%s: opened pipe %s to machine %s "
+                 "for domain %s and bound using schannel.\n",
+                 __func__, table->name,
+                 rpccli->desthost, cli_credentials_get_domain(cli_creds)));
+
+       *_rpccli = rpccli;
+       return NT_STATUS_OK;
 }
 
 NTSTATUS cli_get_session_key(TALLOC_CTX *mem_ctx,
@@ -3210,24 +3317,18 @@ NTSTATUS cli_get_session_key(TALLOC_CTX *mem_ctx,
        }
 
        switch (cli->auth->auth_type) {
-       case DCERPC_AUTH_TYPE_SPNEGO:
-       case DCERPC_AUTH_TYPE_NTLMSSP:
-       case DCERPC_AUTH_TYPE_KRB5:
-               gensec_security = talloc_get_type_abort(a->auth_ctx,
-                                               struct gensec_security);
-               status = gensec_session_key(gensec_security, mem_ctx, &sk);
-               if (!NT_STATUS_IS_OK(status)) {
-                       return status;
-               }
-               make_dup = false;
-               break;
-       case DCERPC_AUTH_TYPE_NCALRPC_AS_SYSTEM:
        case DCERPC_AUTH_TYPE_NONE:
                sk = data_blob_const(a->transport_session_key.data,
                                     a->transport_session_key.length);
                make_dup = true;
                break;
        default:
+               gensec_security = a->auth_ctx;
+               status = gensec_session_key(gensec_security, mem_ctx, &sk);
+               if (!NT_STATUS_IS_OK(status)) {
+                       return status;
+               }
+               make_dup = false;
                break;
        }