TODO NOT NEEDED cli_connect_sock_send/recv return sock_storage
[metze/samba/wip.git] / source3 / libsmb / cliconnect.c
index b1b7e263e5833a661259f06659c63264efab35cd..f612dc2d53afa2d7735e6da4f971914bf713ebe3 100644 (file)
@@ -22,6 +22,7 @@
 
 #include "includes.h"
 #include "libsmb/libsmb.h"
+#include "libsmb/namequery.h"
 #include "auth_info.h"
 #include "../libcli/auth/libcli_auth.h"
 #include "../libcli/auth/spnego.h"
@@ -40,6 +41,7 @@
 #include "../libcli/smb/smb_seal.h"
 #include "lib/param/param.h"
 #include "../libcli/smb/smb2_negotiate_context.h"
+#include "libads/krb5_errs.h"
 
 #define STAR_SMBSERVER "*SMBSERVER"
 
@@ -283,8 +285,9 @@ NTSTATUS cli_session_creds_prepare_krb5(struct cli_state *cli,
 
        auth_requested = cli_credentials_authentication_requested(creds);
        if (auth_requested) {
+               errno = 0;
                user_principal = cli_credentials_get_principal(creds, frame);
-               if (user_principal == NULL) {
+               if (errno != 0) {
                        TALLOC_FREE(frame);
                        return NT_STATUS_NO_MEMORY;
                }
@@ -299,6 +302,10 @@ NTSTATUS cli_session_creds_prepare_krb5(struct cli_state *cli,
                try_kerberos = true;
        }
 
+       if (user_principal == NULL) {
+               try_kerberos = false;
+       }
+
        if (target_hostname == NULL) {
                try_kerberos = false;
        } else if (is_ipaddress(target_hostname)) {
@@ -349,7 +356,7 @@ NTSTATUS cli_session_creds_prepare_krb5(struct cli_state *cli,
                                0 /* no time correction for now */,
                                NULL);
        if (ret != 0) {
-               int dbglvl = DBGLVL_WARNING;
+               int dbglvl = DBGLVL_NOTICE;
 
                if (krb5_state == CRED_MUST_USE_KERBEROS) {
                        dbglvl = DBGLVL_ERR;
@@ -1125,6 +1132,58 @@ static void cli_session_setup_gensec_remote_done(struct tevent_req *subreq)
        cli_session_setup_gensec_local_next(req);
 }
 
+static void cli_session_dump_keys(TALLOC_CTX *mem_ctx,
+                                 struct smbXcli_session *session,
+                                 DATA_BLOB session_key)
+{
+       NTSTATUS status;
+       DATA_BLOB sig = data_blob_null;
+       DATA_BLOB app = data_blob_null;
+       DATA_BLOB enc = data_blob_null;
+       DATA_BLOB dec = data_blob_null;
+       uint64_t sid = smb2cli_session_current_id(session);
+
+       status = smb2cli_session_signing_key(session, mem_ctx, &sig);
+       if (!NT_STATUS_IS_OK(status)) {
+               goto out;
+       }
+       status = smbXcli_session_application_key(session, mem_ctx, &app);
+       if (!NT_STATUS_IS_OK(status)) {
+               goto out;
+       }
+       status = smb2cli_session_encryption_key(session, mem_ctx, &enc);
+       if (!NT_STATUS_IS_OK(status)) {
+               goto out;
+       }
+       status = smb2cli_session_decryption_key(session, mem_ctx, &dec);
+       if (!NT_STATUS_IS_OK(status)) {
+               goto out;
+       }
+
+       DEBUG(0, ("debug encryption: dumping generated session keys\n"));
+       DEBUGADD(0, ("Session Id    "));
+       dump_data(0, (uint8_t*)&sid, sizeof(sid));
+       DEBUGADD(0, ("Session Key   "));
+       dump_data(0, session_key.data, session_key.length);
+       DEBUGADD(0, ("Signing Key   "));
+       dump_data(0, sig.data, sig.length);
+       DEBUGADD(0, ("App Key       "));
+       dump_data(0, app.data, app.length);
+
+       /* In client code, ServerIn is the encryption key */
+
+       DEBUGADD(0, ("ServerIn Key  "));
+       dump_data(0, enc.data, enc.length);
+       DEBUGADD(0, ("ServerOut Key "));
+       dump_data(0, dec.data, dec.length);
+
+out:
+       data_blob_clear_free(&sig);
+       data_blob_clear_free(&app);
+       data_blob_clear_free(&enc);
+       data_blob_clear_free(&dec);
+}
+
 static void cli_session_setup_gensec_ready(struct tevent_req *req)
 {
        struct cli_session_setup_gensec_state *state =
@@ -1192,6 +1251,11 @@ static void cli_session_setup_gensec_ready(struct tevent_req *req)
                if (tevent_req_nterror(req, status)) {
                        return;
                }
+               if (smbXcli_conn_protocol(state->cli->conn) >= PROTOCOL_SMB3_00
+                   && lp_debug_encryption())
+               {
+                       cli_session_dump_keys(state, session, state->session_key);
+               }
        } else {
                struct smbXcli_session *session = state->cli->smb1.session;
                bool active;
@@ -1284,7 +1348,7 @@ static struct tevent_req *cli_session_setup_spnego_send(
 
        status = cli_session_creds_prepare_krb5(cli, creds);
        if (tevent_req_nterror(req, status)) {
-               return tevent_req_post(req, ev);;
+               return tevent_req_post(req, ev);
        }
 
        subreq = cli_session_setup_gensec_send(state, ev, cli, creds,
@@ -2484,9 +2548,12 @@ fail:
 }
 
 struct cli_connect_sock_state {
+       struct sockaddr_storage *addrs;
+       size_t num_addrs;
        const char **called_names;
        const char **calling_names;
        int *called_types;
+       size_t chosen_index;
        int fd;
        uint16_t port;
 };
@@ -2505,9 +2572,8 @@ static struct tevent_req *cli_connect_sock_send(
 {
        struct tevent_req *req, *subreq;
        struct cli_connect_sock_state *state;
-       const char *prog;
        struct sockaddr_storage *addrs;
-       unsigned i, num_addrs;
+       size_t i;
        NTSTATUS status;
 
        req = tevent_req_create(mem_ctx, &state,
@@ -2516,19 +2582,6 @@ static struct tevent_req *cli_connect_sock_send(
                return NULL;
        }
 
-       prog = getenv("LIBSMB_PROG");
-       if (prog != NULL) {
-               state->fd = sock_exec(prog);
-               if (state->fd == -1) {
-                       status = map_nt_error_from_unix(errno);
-                       tevent_req_nterror(req, status);
-               } else {
-                       state->port = 0;
-                       tevent_req_done(req);
-               }
-               return tevent_req_post(req, ev);
-       }
-
        if ((pss == NULL) || is_zero_addr(pss)) {
 
                /*
@@ -2538,18 +2591,18 @@ static struct tevent_req *cli_connect_sock_send(
                 */
 
                status = resolve_name_list(state, host, name_type,
-                                          &addrs, &num_addrs);
+                                          &state->addrs, &state->num_addrs);
                if (!NT_STATUS_IS_OK(status)) {
                        tevent_req_nterror(req, status);
                        return tevent_req_post(req, ev);
                }
        } else {
-               addrs = talloc_array(state, struct sockaddr_storage, 1);
-               if (tevent_req_nomem(addrs, req)) {
+               state->addrs = talloc_array(state, struct sockaddr_storage, 1);
+               if (tevent_req_nomem(state->addrs, req)) {
                        return tevent_req_post(req, ev);
                }
-               addrs[0] = *pss;
-               num_addrs = 1;
+               state->addrs[0] = *pss;
+               state->num_addrs = 1;
        }
 
        state->called_names = talloc_array(state, const char *, num_addrs);
@@ -2564,15 +2617,16 @@ static struct tevent_req *cli_connect_sock_send(
        if (tevent_req_nomem(state->calling_names, req)) {
                return tevent_req_post(req, ev);
        }
-       for (i=0; i<num_addrs; i++) {
+       for (i=0; i<state->num_addrs; i++) {
                state->called_names[i] = host;
                state->called_types[i] = name_type;
                state->calling_names[i] = myname;
        }
 
        subreq = smbsock_any_connect_send(
-               state, ev, addrs, state->called_names, state->called_types,
-               state->calling_names, NULL, num_addrs, port);
+               state, ev, state->addrs,
+               state->called_names, state->called_types, state->calling_names,
+               NULL, state->num_addrs, port);
        if (tevent_req_nomem(subreq, req)) {
                return tevent_req_post(req, ev);
        }
@@ -2588,7 +2642,8 @@ static void cli_connect_sock_done(struct tevent_req *subreq)
                req, struct cli_connect_sock_state);
        NTSTATUS status;
 
-       status = smbsock_any_connect_recv(subreq, &state->fd, NULL,
+       status = smbsock_any_connect_recv(subreq, &state->fd,
+                                         &state->chosen_index,
                                          &state->port);
        TALLOC_FREE(subreq);
        if (tevent_req_nterror(req, status)) {
@@ -2599,7 +2654,9 @@ static void cli_connect_sock_done(struct tevent_req *subreq)
 }
 
 static NTSTATUS cli_connect_sock_recv(struct tevent_req *req,
-                                     int *pfd, uint16_t *pport)
+                                     int *pfd,
+                                     struct sockaddr_storage *pss,
+                                     uint16_t *pport)
 {
        struct cli_connect_sock_state *state = tevent_req_data(
                req, struct cli_connect_sock_state);
@@ -2609,6 +2666,7 @@ static NTSTATUS cli_connect_sock_recv(struct tevent_req *req,
                return status;
        }
        *pfd = state->fd;
+       *pss = state->addrs[state->chosen_index];
        *pport = state->port;
        return NT_STATUS_OK;
 }
@@ -2784,6 +2842,11 @@ static struct tevent_req *cli_start_connection_send(
                state->max_protocol = MIN(state->max_protocol, PROTOCOL_NT1);
        }
 
+       if (flags & CLI_FULL_CONNECTION_DISABLE_SMB1) {
+               state->min_protocol = MAX(state->max_protocol, PROTOCOL_SMB2_02);
+               state->max_protocol = MAX(state->max_protocol, PROTOCOL_LATEST);
+       }
+
        subreq = cli_connect_nb_send(state, ev, dest_host, dest_ss, port,
                                     0x20, my_name, signing_state, flags);
        if (tevent_req_nomem(subreq, req)) {
@@ -3741,6 +3804,8 @@ struct cli_state *get_ipc_connect(char *server,
                flags |= CLI_FULL_CONNECTION_USE_KERBEROS;
        }
 
+       flags |= CLI_FULL_CONNECTION_FORCE_SMB1;
+
        nt_status = cli_full_connection(&cli, NULL, server, server_ss, 0, "IPC$", "IPC", 
                                        get_cmdline_auth_info_username(user_info),
                                        lp_workgroup(),