s3:libsmb: change cli_full_connection_send/recv into cli_full_connection_creds_send...
authorStefan Metzmacher <metze@samba.org>
Wed, 26 Oct 2016 11:48:58 +0000 (13:48 +0200)
committerAndreas Schneider <asn@cryptomilk.org>
Fri, 2 Dec 2016 12:46:11 +0000 (13:46 +0100)
Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Andreas Schneider <asn@samba.org>
source3/libsmb/cliconnect.c
source3/libsmb/proto.h
source3/libsmb/pylibsmb.c

index 7f82d4b48e6544684181a1d8aab1341c3dcfb484..b310a79d436229ac6aefb71feb7aeff2b8c6d7c4 100644 (file)
@@ -2830,72 +2830,86 @@ fail:
    @param port (optional) The destination port (0 for default)
    @param service (optional) The share to make the connection to.  Should be 'unqualified' in any way.
    @param service_type The 'type' of serivice. 
-   @param user Username, unix string
-   @param domain User's domain
-   @param password User's password, unencrypted unix string.
+   @param creds The used user credentials
 */
 
-struct cli_full_connection_state {
+struct cli_full_connection_creds_state {
        struct tevent_context *ev;
        const char *service;
        const char *service_type;
-       const char *user;
-       const char *domain;
-       const char *password;
-       int pw_len;
+       struct cli_credentials *creds;
        int flags;
        struct cli_state *cli;
 };
 
-static int cli_full_connection_state_destructor(
-       struct cli_full_connection_state *s);
-static void cli_full_connection_started(struct tevent_req *subreq);
-static void cli_full_connection_sess_set_up(struct tevent_req *subreq);
-static void cli_full_connection_done(struct tevent_req *subreq);
+static int cli_full_connection_creds_state_destructor(
+       struct cli_full_connection_creds_state *s);
+static void cli_full_connection_creds_started(struct tevent_req *subreq);
+static void cli_full_connection_creds_sess_set_up(struct tevent_req *subreq);
+static void cli_full_connection_creds_done(struct tevent_req *subreq);
 
-struct tevent_req *cli_full_connection_send(
+struct tevent_req *cli_full_connection_creds_send(
        TALLOC_CTX *mem_ctx, struct tevent_context *ev,
        const char *my_name, const char *dest_host,
        const struct sockaddr_storage *dest_ss, int port,
        const char *service, const char *service_type,
-       const char *user, const char *domain,
-       const char *password, int flags, int signing_state)
+       struct cli_credentials *creds,
+       int flags, int signing_state)
 {
        struct tevent_req *req, *subreq;
-       struct cli_full_connection_state *state;
+       struct cli_full_connection_creds_state *state;
+       enum credentials_use_kerberos krb5_state;
+       uint32_t gensec_features = 0;
 
        req = tevent_req_create(mem_ctx, &state,
-                               struct cli_full_connection_state);
+                               struct cli_full_connection_creds_state);
        if (req == NULL) {
                return NULL;
        }
-       talloc_set_destructor(state, cli_full_connection_state_destructor);
+       talloc_set_destructor(state, cli_full_connection_creds_state_destructor);
+
+       flags &= ~CLI_FULL_CONNECTION_USE_KERBEROS;
+       flags &= ~CLI_FULL_CONNECTION_FALLBACK_AFTER_KERBEROS;
+       flags &= ~CLI_FULL_CONNECTION_USE_CCACHE;
+       flags &= ~CLI_FULL_CONNECTION_USE_NT_HASH;
+
+       krb5_state = cli_credentials_get_kerberos_state(creds);
+       switch (krb5_state) {
+       case CRED_MUST_USE_KERBEROS:
+               flags |= CLI_FULL_CONNECTION_USE_KERBEROS;
+               flags &= ~CLI_FULL_CONNECTION_DONT_SPNEGO;
+               break;
+       case CRED_AUTO_USE_KERBEROS:
+               flags |= CLI_FULL_CONNECTION_USE_KERBEROS;
+               flags |= CLI_FULL_CONNECTION_FALLBACK_AFTER_KERBEROS;
+               break;
+       case CRED_DONT_USE_KERBEROS:
+               break;
+       }
+
+       gensec_features = cli_credentials_get_gensec_features(creds);
+       if (gensec_features & GENSEC_FEATURE_NTLM_CCACHE) {
+               flags |= CLI_FULL_CONNECTION_USE_CCACHE;
+       }
 
        state->ev = ev;
        state->service = service;
        state->service_type = service_type;
-       state->user = user;
-       state->domain = domain;
-       state->password = password;
+       state->creds = creds;
        state->flags = flags;
 
-       state->pw_len = state->password ? strlen(state->password)+1 : 0;
-       if (state->password == NULL) {
-               state->password = "";
-       }
-
        subreq = cli_start_connection_send(
                state, ev, my_name, dest_host, dest_ss, port,
                signing_state, flags);
        if (tevent_req_nomem(subreq, req)) {
                return tevent_req_post(req, ev);
        }
-       tevent_req_set_callback(subreq, cli_full_connection_started, req);
+       tevent_req_set_callback(subreq, cli_full_connection_creds_started, req);
        return req;
 }
 
-static int cli_full_connection_state_destructor(
-       struct cli_full_connection_state *s)
+static int cli_full_connection_creds_state_destructor(
+       struct cli_full_connection_creds_state *s)
 {
        if (s->cli != NULL) {
                cli_shutdown(s->cli);
@@ -2904,14 +2918,13 @@ static int cli_full_connection_state_destructor(
        return 0;
 }
 
-static void cli_full_connection_started(struct tevent_req *subreq)
+static void cli_full_connection_creds_started(struct tevent_req *subreq)
 {
        struct tevent_req *req = tevent_req_callback_data(
                subreq, struct tevent_req);
-       struct cli_full_connection_state *state = tevent_req_data(
-               req, struct cli_full_connection_state);
+       struct cli_full_connection_creds_state *state = tevent_req_data(
+               req, struct cli_full_connection_creds_state);
        NTSTATUS status;
-       struct cli_credentials *creds = NULL;
 
        status = cli_start_connection_recv(subreq, &state->cli);
        TALLOC_FREE(subreq);
@@ -2919,33 +2932,20 @@ static void cli_full_connection_started(struct tevent_req *subreq)
                return;
        }
 
-       creds = cli_session_creds_init(state,
-                                      state->user,
-                                      state->domain,
-                                      NULL, /* realm (use default) */
-                                      state->password,
-                                      state->cli->use_kerberos,
-                                      state->cli->fallback_after_kerberos,
-                                      state->cli->use_ccache,
-                                      state->cli->pw_nt_hash);
-       if (tevent_req_nomem(creds, req)) {
-               return;
-       }
-
        subreq = cli_session_setup_creds_send(
-               state, state->ev, state->cli, creds);
+               state, state->ev, state->cli, state->creds);
        if (tevent_req_nomem(subreq, req)) {
                return;
        }
-       tevent_req_set_callback(subreq, cli_full_connection_sess_set_up, req);
+       tevent_req_set_callback(subreq, cli_full_connection_creds_sess_set_up, req);
 }
 
-static void cli_full_connection_sess_set_up(struct tevent_req *subreq)
+static void cli_full_connection_creds_sess_set_up(struct tevent_req *subreq)
 {
        struct tevent_req *req = tevent_req_callback_data(
                subreq, struct tevent_req);
-       struct cli_full_connection_state *state = tevent_req_data(
-               req, struct cli_full_connection_state);
+       struct cli_full_connection_creds_state *state = tevent_req_data(
+               req, struct cli_full_connection_creds_state);
        NTSTATUS status;
 
        status = cli_session_setup_creds_recv(subreq);
@@ -2953,22 +2953,21 @@ static void cli_full_connection_sess_set_up(struct tevent_req *subreq)
 
        if (!NT_STATUS_IS_OK(status) &&
            (state->flags & CLI_FULL_CONNECTION_ANONYMOUS_FALLBACK)) {
-               struct cli_credentials *creds = NULL;
 
                state->flags &= ~CLI_FULL_CONNECTION_ANONYMOUS_FALLBACK;
 
-               creds = cli_credentials_init_anon(state);
-               if (tevent_req_nomem(creds, req)) {
+               state->creds = cli_credentials_init_anon(state);
+               if (tevent_req_nomem(state->creds, req)) {
                        return;
                }
 
                subreq = cli_session_setup_creds_send(
-                       state, state->ev, state->cli, creds);
+                       state, state->ev, state->cli, state->creds);
                if (tevent_req_nomem(subreq, req)) {
                        return;
                }
                tevent_req_set_callback(
-                       subreq, cli_full_connection_sess_set_up, req);
+                       subreq, cli_full_connection_creds_sess_set_up, req);
                return;
        }
 
@@ -2977,21 +2976,28 @@ static void cli_full_connection_sess_set_up(struct tevent_req *subreq)
        }
 
        if (state->service != NULL) {
+               const char *password = cli_credentials_get_password(state->creds);
+               int pw_len = password ? strlen(password)+1 : 0;
+
+               if (password == NULL) {
+                       password = "";
+               }
+
                subreq = cli_tree_connect_send(
                        state, state->ev, state->cli,
                        state->service, state->service_type,
-                       state->password, state->pw_len);
+                       password, pw_len);
                if (tevent_req_nomem(subreq, req)) {
                        return;
                }
-               tevent_req_set_callback(subreq, cli_full_connection_done, req);
+               tevent_req_set_callback(subreq, cli_full_connection_creds_done, req);
                return;
        }
 
        tevent_req_done(req);
 }
 
-static void cli_full_connection_done(struct tevent_req *subreq)
+static void cli_full_connection_creds_done(struct tevent_req *subreq)
 {
        struct tevent_req *req = tevent_req_callback_data(
                subreq, struct tevent_req);
@@ -3006,11 +3012,11 @@ static void cli_full_connection_done(struct tevent_req *subreq)
        tevent_req_done(req);
 }
 
-NTSTATUS cli_full_connection_recv(struct tevent_req *req,
+NTSTATUS cli_full_connection_creds_recv(struct tevent_req *req,
                                  struct cli_state **output_cli)
 {
-       struct cli_full_connection_state *state = tevent_req_data(
-               req, struct cli_full_connection_state);
+       struct cli_full_connection_creds_state *state = tevent_req_data(
+               req, struct cli_full_connection_creds_state);
        NTSTATUS status;
 
        if (tevent_req_is_nterror(req, &status)) {
@@ -3021,14 +3027,14 @@ NTSTATUS cli_full_connection_recv(struct tevent_req *req,
        return NT_STATUS_OK;
 }
 
-NTSTATUS cli_full_connection(struct cli_state **output_cli,
-                            const char *my_name,
-                            const char *dest_host,
-                            const struct sockaddr_storage *dest_ss, int port,
-                            const char *service, const char *service_type,
-                            const char *user, const char *domain,
-                            const char *password, int flags,
-                            int signing_state)
+NTSTATUS cli_full_connection_creds(struct cli_state **output_cli,
+                                  const char *my_name,
+                                  const char *dest_host,
+                                  const struct sockaddr_storage *dest_ss, int port,
+                                  const char *service, const char *service_type,
+                                  struct cli_credentials *creds,
+                                  int flags,
+                                  int signing_state)
 {
        struct tevent_context *ev;
        struct tevent_req *req;
@@ -3038,21 +3044,81 @@ NTSTATUS cli_full_connection(struct cli_state **output_cli,
        if (ev == NULL) {
                goto fail;
        }
-       req = cli_full_connection_send(
+       req = cli_full_connection_creds_send(
                ev, ev, my_name, dest_host, dest_ss, port, service,
-               service_type, user, domain, password, flags, signing_state);
+               service_type, creds, flags, signing_state);
        if (req == NULL) {
                goto fail;
        }
        if (!tevent_req_poll_ntstatus(req, ev, &status)) {
                goto fail;
        }
-       status = cli_full_connection_recv(req, output_cli);
+       status = cli_full_connection_creds_recv(req, output_cli);
  fail:
        TALLOC_FREE(ev);
        return status;
 }
 
+NTSTATUS cli_full_connection(struct cli_state **output_cli,
+                            const char *my_name,
+                            const char *dest_host,
+                            const struct sockaddr_storage *dest_ss, int port,
+                            const char *service, const char *service_type,
+                            const char *user, const char *domain,
+                            const char *password, int flags,
+                            int signing_state)
+{
+       TALLOC_CTX *frame = talloc_stackframe();
+       NTSTATUS status;
+       bool use_kerberos = false;
+       bool fallback_after_kerberos = false;
+       bool use_ccache = false;
+       bool pw_nt_hash = false;
+       struct cli_credentials *creds = NULL;
+
+       if (flags & CLI_FULL_CONNECTION_USE_KERBEROS) {
+               use_kerberos = true;
+       }
+
+       if (flags & CLI_FULL_CONNECTION_FALLBACK_AFTER_KERBEROS) {
+               fallback_after_kerberos = true;
+       }
+
+       if (flags & CLI_FULL_CONNECTION_USE_CCACHE) {
+               use_ccache = true;
+       }
+
+       if (flags & CLI_FULL_CONNECTION_USE_NT_HASH) {
+               pw_nt_hash = true;
+       }
+
+       creds = cli_session_creds_init(frame,
+                                      user,
+                                      domain,
+                                      NULL, /* realm (use default) */
+                                      password,
+                                      use_kerberos,
+                                      fallback_after_kerberos,
+                                      use_ccache,
+                                      pw_nt_hash);
+       if (creds == NULL) {
+               TALLOC_FREE(frame);
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       status = cli_full_connection_creds(output_cli, my_name,
+                                          dest_host, dest_ss, port,
+                                          service, service_type,
+                                          creds, flags, signing_state);
+       if (!NT_STATUS_IS_OK(status)) {
+               TALLOC_FREE(frame);
+               return status;
+       }
+
+       TALLOC_FREE(frame);
+       return NT_STATUS_OK;
+}
+
 /****************************************************************************
  Send an old style tcon.
 ****************************************************************************/
index 2191f922e975cbf54ab4591c7f2520fa6a79f70e..107579c7b43f32ee060d41f4f989c1a1d37eeb88 100644 (file)
@@ -89,15 +89,23 @@ NTSTATUS cli_start_connection(struct cli_state **output_cli,
                              const char *dest_host,
                              const struct sockaddr_storage *dest_ss, int port,
                              int signing_state, int flags);
-struct tevent_req *cli_full_connection_send(
+struct tevent_req *cli_full_connection_creds_send(
        TALLOC_CTX *mem_ctx, struct tevent_context *ev,
        const char *my_name, const char *dest_host,
        const struct sockaddr_storage *dest_ss, int port,
        const char *service, const char *service_type,
-       const char *user, const char *domain,
-       const char *password, int flags, int signing_state);
-NTSTATUS cli_full_connection_recv(struct tevent_req *req,
-                                 struct cli_state **output_cli);
+       struct cli_credentials *creds,
+       int flags, int signing_state);
+NTSTATUS cli_full_connection_creds_recv(struct tevent_req *req,
+                                       struct cli_state **output_cli);
+NTSTATUS cli_full_connection_creds(struct cli_state **output_cli,
+                                  const char *my_name,
+                                  const char *dest_host,
+                                  const struct sockaddr_storage *dest_ss, int port,
+                                  const char *service, const char *service_type,
+                                  struct cli_credentials *creds,
+                                  int flags,
+                                  int signing_state);
 NTSTATUS cli_full_connection(struct cli_state **output_cli,
                             const char *my_name,
                             const char *dest_host,
index 0c5d7e94841ee98be438c542992a66f4222620b9..59c09983688d77f127d0dbcda924ebf1b4fc017d 100644 (file)
@@ -442,16 +442,13 @@ static int py_cli_state_init(struct py_cli_state *self, PyObject *args,
                cli_creds = PyCredentials_AsCliCredentials(creds);
        }
 
-       req = cli_full_connection_send(
+       req = cli_full_connection_creds_send(
                NULL, self->ev, "myname", host, NULL, 0, share, "?????",
-               cli_credentials_get_username(cli_creds),
-               cli_credentials_get_domain(cli_creds),
-               cli_credentials_get_password(cli_creds),
-               0, 0);
+               cli_creds, 0, 0);
        if (!py_tevent_req_wait_exc(self->ev, req)) {
                return -1;
        }
-       status = cli_full_connection_recv(req, &self->cli);
+       status = cli_full_connection_creds_recv(req, &self->cli);
        TALLOC_FREE(req);
 
        if (!NT_STATUS_IS_OK(status)) {