Decouple clistr_pull from struct cli_state->inbuf
[metze/samba/wip.git] / source3 / libsmb / clidfs.c
index 7800d10e8be39e39b643316020f4118cd79dcc90..f853e4e6701f6b062e1a90c6108d6b6902ec6d6f 100644 (file)
@@ -38,24 +38,17 @@ struct client_connection {
        char *mount;
 };
 
-/* global state....globals reek! */
-int max_protocol = PROTOCOL_NT1;
-
 static struct cm_cred_struct {
        char *username;
        char *password;
        bool got_pass;
        bool use_kerberos;
+       bool fallback_after_kerberos;
        int signing_state;
 } cm_creds;
 
 static void cm_set_password(const char *newpass);
 
-static int port;
-static int name_type = 0x20;
-static bool have_ip;
-static struct sockaddr_storage dest_ss;
-
 static struct client_connection *connections;
 
 static bool cli_check_msdfs_proxy(TALLOC_CTX *ctx,
@@ -72,54 +65,36 @@ static bool cli_check_msdfs_proxy(TALLOC_CTX *ctx,
  Ensure a connection is encrypted.
 ********************************************************************/
 
-static bool force_cli_encryption(struct cli_state *c,
+NTSTATUS cli_cm_force_encryption(struct cli_state *c,
                        const char *username,
                        const char *password,
                        const char *domain,
                        const char *sharename)
 {
-       uint16 major, minor;
-       uint32 caplow, caphigh;
-       NTSTATUS status;
+       NTSTATUS status = cli_force_encryption(c,
+                                       username,
+                                       password,
+                                       domain);
 
-       if (!SERVER_HAS_UNIX_CIFS(c)) {
+       if (NT_STATUS_EQUAL(status,NT_STATUS_NOT_SUPPORTED)) {
                d_printf("Encryption required and "
                        "server that doesn't support "
                        "UNIX extensions - failing connect\n");
-               return false;
-       }
-
-       if (!cli_unix_extensions_version(c, &major, &minor, &caplow, &caphigh)) {
+       } else if (NT_STATUS_EQUAL(status,NT_STATUS_UNKNOWN_REVISION)) {
                d_printf("Encryption required and "
                        "can't get UNIX CIFS extensions "
                        "version from server.\n");
-               return false;
-       }
-
-       if (!(caplow & CIFS_UNIX_TRANSPORT_ENCRYPTION_CAP)) {
+       } else if (NT_STATUS_EQUAL(status,NT_STATUS_UNSUPPORTED_COMPRESSION)) {
                d_printf("Encryption required and "
                        "share %s doesn't support "
                        "encryption.\n", sharename);
-               return false;
-       }
-
-       if (c->use_kerberos) {
-               status = cli_gss_smb_encryption_start(c);
-       } else {
-               status = cli_raw_ntlm_smb_encryption_start(c,
-                                               username,
-                                               password,
-                                               domain);
-       }
-
-       if (!NT_STATUS_IS_OK(status)) {
+       } else if (!NT_STATUS_IS_OK(status)) {
                d_printf("Encryption required and "
                        "setup failed with error %s.\n",
                        nt_errstr(status));
-               return false;
        }
 
-       return true;
+       return status;
 }
        
 /********************************************************************
@@ -130,7 +105,10 @@ static struct cli_state *do_connect(TALLOC_CTX *ctx,
                                        const char *server,
                                        const char *share,
                                        bool show_sessetup,
-                                       bool force_encrypt)
+                                       bool force_encrypt,
+                                       int max_protocol,
+                                       int port,
+                                       int name_type)
 {
        struct cli_state *c = NULL;
        struct nmb_name called, calling;
@@ -150,8 +128,11 @@ static struct cli_state *do_connect(TALLOC_CTX *ctx,
        }
        sharename = servicename;
        if (*sharename == '\\') {
-               server = sharename+2;
-               sharename = strchr_m(server,'\\');
+               sharename += 2;
+               if (server == NULL) {
+                       server = sharename;
+               }
+               sharename = strchr_m(sharename,'\\');
                if (!sharename) {
                        return NULL;
                }
@@ -161,31 +142,41 @@ static struct cli_state *do_connect(TALLOC_CTX *ctx,
 
        server_n = server;
 
-       zero_addr(&ss);
+       zero_sockaddr(&ss);
 
        make_nmb_name(&calling, global_myname(), 0x0);
        make_nmb_name(&called , server, name_type);
 
  again:
-       zero_addr(&ss);
-       if (have_ip)
-               ss = dest_ss;
+       zero_sockaddr(&ss);
 
        /* have to open a new connection */
-       if (!(c=cli_initialise()) || (cli_set_port(c, port) != port)) {
+       if (!(c=cli_initialise())) {
                d_printf("Connection to %s failed\n", server_n);
+               if (c) {
+                       cli_shutdown(c);
+               }
                return NULL;
        }
+       if (port) {
+               cli_set_port(c, port);
+       }
+
        status = cli_connect(c, server_n, &ss);
        if (!NT_STATUS_IS_OK(status)) {
                d_printf("Connection to %s failed (Error %s)\n",
                                server_n,
                                nt_errstr(status));
+               cli_shutdown(c);
                return NULL;
        }
 
+       if (max_protocol == 0) {
+               max_protocol = PROTOCOL_NT1;
+       }
        c->protocol = max_protocol;
        c->use_kerberos = cm_creds.use_kerberos;
+       c->fallback_after_kerberos = cm_creds.fallback_after_kerberos;
        cli_setup_signing_state(c, cm_creds.signing_state);
 
        if (!cli_session_request(c, &calling, &called)) {
@@ -207,17 +198,25 @@ static struct cli_state *do_connect(TALLOC_CTX *ctx,
 
        DEBUG(4,(" session request ok\n"));
 
-       if (!cli_negprot(c)) {
-               d_printf("protocol negotiation failed\n");
+       status = cli_negprot(c);
+
+       if (!NT_STATUS_IS_OK(status)) {
+               d_printf("protocol negotiation failed: %s\n",
+                        nt_errstr(status));
                cli_shutdown(c);
                return NULL;
        }
 
-       if (!cm_creds.got_pass) {
-               char *pass = getpass("Password: ");
+       if (!cm_creds.got_pass && !cm_creds.use_kerberos) {
+               char *label = NULL;
+               char *pass;
+               label = talloc_asprintf(ctx, "Enter %s's password: ",
+                       cm_creds.username);
+               pass = getpass(label);
                if (pass) {
                        cm_set_password(pass);
                }
+               TALLOC_FREE(label);
        }
 
        username = cm_creds.username ? cm_creds.username : "";
@@ -269,7 +268,9 @@ static struct cli_state *do_connect(TALLOC_CTX *ctx,
                                lp_workgroup())) {
                cli_shutdown(c);
                return do_connect(ctx, newserver,
-                               newshare, false, force_encrypt);
+                               newshare, false,
+                               force_encrypt, max_protocol,
+                               port, name_type);
        }
 
        /* must be a normal share */
@@ -281,13 +282,16 @@ static struct cli_state *do_connect(TALLOC_CTX *ctx,
                return NULL;
        }
 
-       if (force_encrypt && !force_cli_encryption(c,
+       if (force_encrypt) {
+               status = cli_cm_force_encryption(c,
                                        username,
                                        password,
                                        lp_workgroup(),
-                                       sharename)) {
-               cli_shutdown(c);
-               return NULL;
+                                       sharename);
+               if (!NT_STATUS_IS_OK(status)) {
+                       cli_shutdown(c);
+                       return NULL;
+               }
        }
 
        DEBUG(4,(" tconx ok\n"));
@@ -310,10 +314,11 @@ static void cli_cm_set_mntpoint(struct cli_state *c, const char *mnt)
        }
 
        if (p) {
-               char *name = clean_name(NULL, p->mount);
+               char *name = clean_name(NULL, mnt);
                if (!name) {
                        return;
                }
+               TALLOC_FREE(p->mount);
                p->mount = talloc_strdup(p, name);
                TALLOC_FREE(name);
        }
@@ -349,7 +354,10 @@ static struct cli_state *cli_cm_connect(TALLOC_CTX *ctx,
                                        const char *server,
                                        const char *share,
                                        bool show_hdr,
-                                       bool force_encrypt)
+                                       bool force_encrypt,
+                                       int max_protocol,
+                                       int port,
+                                       int name_type)
 {
        struct client_connection *node;
 
@@ -359,7 +367,9 @@ static struct cli_state *cli_cm_connect(TALLOC_CTX *ctx,
                return NULL;
        }
 
-       node->cli = do_connect(ctx, server, share, show_hdr, force_encrypt);
+       node->cli = do_connect(ctx, server, share,
+                               show_hdr, force_encrypt, max_protocol,
+                               port, name_type);
 
        if ( !node->cli ) {
                TALLOC_FREE( node );
@@ -412,7 +422,10 @@ struct cli_state *cli_cm_open(TALLOC_CTX *ctx,
                                const char *server,
                                const char *share,
                                bool show_hdr,
-                               bool force_encrypt)
+                               bool force_encrypt,
+                               int max_protocol,
+                               int port,
+                               int name_type)
 {
        struct cli_state *c;
 
@@ -421,7 +434,8 @@ struct cli_state *cli_cm_open(TALLOC_CTX *ctx,
        c = cli_cm_find(server, share);
        if (!c) {
                c = cli_cm_connect(ctx, referring_cli,
-                               server, share, show_hdr, force_encrypt);
+                               server, share, show_hdr, force_encrypt,
+                               max_protocol, port, name_type);
        }
 
        return c;
@@ -472,42 +486,67 @@ static void cm_set_password(const char *newpass)
        }
 }
 
-void cli_cm_set_credentials(void)
+/****************************************************************************
+****************************************************************************/
+
+void cli_cm_set_credentials(struct user_auth_info *auth_info)
 {
        SAFE_FREE(cm_creds.username);
-       cm_creds.username = SMB_STRDUP(get_cmdline_auth_info_username());
+       cm_creds.username = SMB_STRDUP(get_cmdline_auth_info_username(
+                                              auth_info));
 
-       if (get_cmdline_auth_info_got_pass()) {
-               cm_set_password(get_cmdline_auth_info_password());
+       if (get_cmdline_auth_info_got_pass(auth_info)) {
+               cm_set_password(get_cmdline_auth_info_password(auth_info));
        }
 
-       cm_creds.use_kerberos = get_cmdline_auth_info_use_kerberos();
-       cm_creds.signing_state = get_cmdline_auth_info_signing_state();
+       cm_creds.use_kerberos = get_cmdline_auth_info_use_kerberos(auth_info);
+       cm_creds.fallback_after_kerberos = false;
+       cm_creds.signing_state = get_cmdline_auth_info_signing_state(auth_info);
 }
 
 /****************************************************************************
 ****************************************************************************/
 
-void cli_cm_set_port(int port_number)
+void cli_cm_set_signing_state(int state)
 {
-       port = port_number;
+       cm_creds.signing_state = state;
 }
 
 /****************************************************************************
 ****************************************************************************/
 
-void cli_cm_set_dest_name_type(int type)
+void cli_cm_set_username(const char *username)
 {
-       name_type = type;
+       SAFE_FREE(cm_creds.username);
+       cm_creds.username = SMB_STRDUP(username);
 }
 
 /****************************************************************************
 ****************************************************************************/
 
-void cli_cm_set_dest_ss(struct sockaddr_storage *pss)
+void cli_cm_set_password(const char *newpass)
 {
-       dest_ss = *pss;
-       have_ip = true;
+       SAFE_FREE(cm_creds.password);
+       cm_creds.password = SMB_STRDUP(newpass);
+       if (cm_creds.password) {
+               cm_creds.got_pass = true;
+       }
+}
+
+/****************************************************************************
+****************************************************************************/
+
+void cli_cm_set_use_kerberos(void)
+{
+       cm_creds.use_kerberos = true;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+void cli_cm_set_fallback_after_kerberos(void)
+{
+       cm_creds.fallback_after_kerberos = true;
 }
 
 /**********************************************************************
@@ -746,9 +785,10 @@ bool cli_dfs_get_referral(TALLOC_CTX *ctx,
                        if (p + node_offset > endp) {
                                goto out;
                        }
-                       clistr_pull_talloc(ctx, cli, &referrals[i].dfspath,
-                               p+node_offset, -1,
-                               STR_TERMINATE|STR_UNICODE );
+                       clistr_pull_talloc(ctx, cli->inbuf,
+                                          &referrals[i].dfspath,
+                                          p+node_offset, -1,
+                                          STR_TERMINATE|STR_UNICODE);
 
                        if (!referrals[i].dfspath) {
                                goto out;
@@ -860,7 +900,10 @@ bool cli_resolve_path(TALLOC_CTX *ctx,
        if (!(cli_ipc = cli_cm_open(ctx, rootcli,
                                        rootcli->desthost,
                                        "IPC$", false,
-                                       (rootcli->trans_enc_state != NULL)))) {
+                                       (rootcli->trans_enc_state != NULL),
+                                       rootcli->protocol,
+                                       0,
+                                       0x20))) {
                return false;
        }
 
@@ -905,7 +948,10 @@ bool cli_resolve_path(TALLOC_CTX *ctx,
                                        server,
                                        share,
                                        false,
-                                       (rootcli->trans_enc_state != NULL))) == NULL) {
+                                       (rootcli->trans_enc_state != NULL),
+                                       rootcli->protocol,
+                                       0,
+                                       0x20)) == NULL) {
                d_printf("Unable to follow dfs referral [\\%s\\%s]\n",
                        server, share );
                return false;
@@ -1035,12 +1081,15 @@ static bool cli_check_msdfs_proxy(TALLOC_CTX *ctx,
                return false;
        }
 
-       if (force_encrypt && !force_cli_encryption(cli,
+       if (force_encrypt) {
+               NTSTATUS status = cli_cm_force_encryption(cli,
                                        username,
                                        password,
                                        lp_workgroup(),
-                                       "IPC$")) {
-               return false;
+                                       "IPC$");
+               if (!NT_STATUS_IS_OK(status)) {
+                       return false;
+               }
        }
 
        res = cli_dfs_get_referral(ctx, cli, fullpath, &refs, &num_refs, &consumed);
@@ -1062,7 +1111,7 @@ static bool cli_check_msdfs_proxy(TALLOC_CTX *ctx,
        split_dfs_path(ctx, refs[0].dfspath, pp_newserver,
                        pp_newshare, &newextrapath );
 
-       if (!pp_newserver || !pp_newshare) {
+       if ((*pp_newserver == NULL) || (*pp_newshare == NULL)) {
                return false;
        }