Fix up 'net ads join' to delete and rejoin if the account already exists.
[ira/wip.git] / source3 / libsmb / cliconnect.c
index 2a84b69faa605816d71c0e45a124ae34cc9d091d..7649a88ffdd56778ccb7583778f2b387baf2252f 100644 (file)
@@ -117,10 +117,7 @@ static uint32 cli_session_setup_capabilities(struct cli_state *cli)
 {
        uint32 capabilities = CAP_NT_SMBS;
 
-       /* Set the CLI_FORCE_DOSERR environment variable to test
-          client routines using DOS errors instead of STATUS32
-          ones.  This intended only as a temporary hack. */    
-       if (!getenv("CLI_FORCE_DOSERR")) {
+       if (!cli->force_dos_errors) {
                capabilities |= CAP_STATUS32;
        }
 
@@ -197,7 +194,7 @@ static BOOL cli_session_setup_plaintext(struct cli_state *cli, char *user,
        int passlen;
        char *p;
 
-       passlen = clistr_push(cli, pword, pass, sizeof(pword), STR_TERMINATE);
+       passlen = clistr_push(cli, pword, pass, sizeof(pword), STR_TERMINATE|STR_ASCII);
 
        set_message(cli->outbuf,13,0,True);
        CVAL(cli->outbuf,smb_com) = SMBsesssetupX;
@@ -258,11 +255,13 @@ static BOOL cli_session_setup_nt1(struct cli_state *cli, char *user,
        }
 
        if (passlen != 24) {
-               /* non encrypted password supplied. */
+               /* non encrypted password supplied. Ignore ntpass. */
                passlen = 24;
                ntpasslen = 24;
-               clistr_push(cli, pword, pass, sizeof(pword), STR_TERMINATE);
-               clistr_push(cli, ntpword, ntpass, sizeof(ntpword), STR_TERMINATE);
+               clistr_push(cli, pword, 
+                           pass?pass:"", sizeof(pword), STR_TERMINATE|STR_ASCII);
+               clistr_push(cli, ntpword, 
+                           pass?pass:"", sizeof(ntpword), STR_TERMINATE|STR_ASCII);
                SMBencrypt((uchar *)pword,cli->secblob.data,(uchar *)pword);
                SMBNTencrypt((uchar *)ntpword,cli->secblob.data,(uchar *)ntpword);
        } else {
@@ -326,6 +325,7 @@ static DATA_BLOB cli_session_setup_blob(struct cli_state *cli, DATA_BLOB blob)
        uint32 capabilities = cli_session_setup_capabilities(cli);
        char *p;
        DATA_BLOB blob2;
+       uint32 len;
 
        blob2 = data_blob(NULL, 0);
 
@@ -341,7 +341,7 @@ static DATA_BLOB cli_session_setup_blob(struct cli_state *cli, DATA_BLOB blob)
        CVAL(cli->outbuf,smb_vwv0) = 0xFF;
        SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
        SSVAL(cli->outbuf,smb_vwv3,2);
-       SSVAL(cli->outbuf,smb_vwv4,0);
+       SSVAL(cli->outbuf,smb_vwv4,1);
        SIVAL(cli->outbuf,smb_vwv5,0);
        SSVAL(cli->outbuf,smb_vwv7,blob.length);
        SIVAL(cli->outbuf,smb_vwv10,capabilities); 
@@ -372,14 +372,16 @@ static DATA_BLOB cli_session_setup_blob(struct cli_state *cli, DATA_BLOB blob)
 
        p += blob2.length;
        p += clistr_pull(cli, cli->server_os, p, sizeof(fstring), -1, STR_TERMINATE);
-       p += clistr_pull(cli, cli->server_type, p, sizeof(fstring), -1, STR_TERMINATE);
-       p += clistr_pull(cli, cli->server_domain, p, sizeof(fstring), -1, STR_TERMINATE);
+
+       /* w2k with kerberos doesn't properly null terminate this field */
+       len = smb_buflen(cli->inbuf) - PTR_DIFF(p, smb_buf(cli->inbuf));
+       p += clistr_pull(cli, cli->server_type, p, sizeof(fstring), len, 0);
 
        return blob2;
 }
 
 
-#if HAVE_KRB5
+#ifdef HAVE_KRB5
 /****************************************************************************
 do a spnego/kerberos encrypted session setup
 ****************************************************************************/
@@ -387,7 +389,7 @@ static BOOL cli_session_setup_kerberos(struct cli_state *cli, char *principal, c
 {
        DATA_BLOB blob2, negTokenTarg;
 
-       d_printf("Doing kerberos session setup\n");
+       DEBUG(2,("Doing kerberos session setup\n"));
 
        /* generate the encapsulated kerberos5 ticket */
        negTokenTarg = spnego_gen_negTokenTarg(cli, principal);
@@ -403,6 +405,8 @@ static BOOL cli_session_setup_kerberos(struct cli_state *cli, char *principal, c
        /* we don't need this blob for kerberos */
        data_blob_free(&blob2);
 
+       data_blob_free(&negTokenTarg);
+
        return !cli_is_error(cli);
 }
 #endif
@@ -511,7 +515,7 @@ static BOOL cli_session_setup_spnego(struct cli_state *cli, char *user,
        int i;
        BOOL got_kerberos_mechanism = False;
 
-       d_printf("Doing spnego session setup\n");
+       DEBUG(2,("Doing spnego session setup (blob length=%d)\n", cli->secblob.length));
 
        /* the server might not even do spnego */
        if (cli->secblob.length == 16) {
@@ -542,7 +546,7 @@ static BOOL cli_session_setup_spnego(struct cli_state *cli, char *user,
 
        fstrcpy(cli->user_name, user);
 
-#if HAVE_KRB5
+#ifdef HAVE_KRB5
        if (got_kerberos_mechanism && cli->use_kerberos) {
                return cli_session_setup_kerberos(cli, principal, workgroup);
        }
@@ -572,7 +576,8 @@ BOOL cli_session_setup(struct cli_state *cli,
 
        /* allow for workgroups as part of the username */
        fstrcpy(user2, user);
-       if ((p=strchr_m(user2,'\\')) || (p=strchr_m(user2,'/'))) {
+       if ((p=strchr_m(user2,'\\')) || (p=strchr_m(user2,'/')) ||
+           (p=strchr_m(user2,*lp_winbind_separator()))) {
                *p = 0;
                user = p+1;
                workgroup = user2;
@@ -708,17 +713,12 @@ BOOL cli_send_tconX(struct cli_state *cli,
                return False;
        }
 
-       fstrcpy(cli->dev, "A:");
-
-       if (cli->protocol >= PROTOCOL_NT1) {
-               clistr_pull(cli, cli->dev, smb_buf(cli->inbuf), sizeof(fstring), -1, STR_TERMINATE);
-       }
+       clistr_pull(cli, cli->dev, smb_buf(cli->inbuf), sizeof(fstring), -1, STR_TERMINATE|STR_ASCII);
 
        if (strcasecmp(share,"IPC$")==0) {
                fstrcpy(cli->dev, "IPC");
        }
 
-       /* only grab the device if we have a recent protocol level */
        if (cli->protocol >= PROTOCOL_NT1 &&
            smb_buflen(cli->inbuf) == 3) {
                /* almost certainly win95 - enable bug fixes */
@@ -842,7 +842,8 @@ BOOL cli_negprot(struct cli_state *cli)
                        cli->writebraw_supported = True;      
                }
                /* work out if they sent us a workgroup */
-               if (smb_buflen(cli->inbuf) > 8) {
+               if (!(cli->capabilities & CAP_EXTENDED_SECURITY) &&
+                   smb_buflen(cli->inbuf) > 8) {
                        clistr_pull(cli, cli->server_domain, 
                                    smb_buf(cli->inbuf)+8, sizeof(cli->server_domain),
                                    smb_buflen(cli->inbuf)-8, STR_UNICODE|STR_NOALIGN);
@@ -977,13 +978,23 @@ open the client sockets
 ****************************************************************************/
 BOOL cli_connect(struct cli_state *cli, const char *host, struct in_addr *ip)
 {
-       extern struct in_addr ipzero;
        extern pstring user_socket_options;
+       int name_type = 0x20;
+       char *p;
+
+       /* reasonable default hostname */
+       if (!host) host = "*SMBSERVER";
 
        fstrcpy(cli->desthost, host);
+
+       /* allow hostnames of the form NAME#xx and do a netbios lookup */
+       if ((p = strchr(cli->desthost, '#'))) {
+               name_type = strtol(p+1, NULL, 16);              
+               *p = 0;
+       }
        
-       if (!ip || ip_equal(*ip, ipzero)) {
-                if (!resolve_name( cli->desthost, &cli->dest_ip, 0x20)) {
+       if (!ip || is_zero_ip(*ip)) {
+                if (!resolve_name(cli->desthost, &cli->dest_ip, name_type)) {
                         return False;
                 }
                if (ip) *ip = cli->dest_ip;
@@ -1017,58 +1028,7 @@ BOOL cli_connect(struct cli_state *cli, const char *host, struct in_addr *ip)
 }
 
 /****************************************************************************
-re-establishes a connection
-****************************************************************************/
-BOOL cli_reestablish_connection(struct cli_state *cli)
-{
-       struct nmb_name calling;
-       struct nmb_name called;
-       fstring dest_host;
-       fstring share;
-       fstring dev;
-       BOOL do_tcon = False;
-       int oldfd = cli->fd;
-
-       if (!cli->initialised || cli->fd == -1)
-       {
-               DEBUG(3,("cli_reestablish_connection: not connected\n"));
-               return False;
-       }
-
-       /* copy the parameters necessary to re-establish the connection */
-
-       if (cli->cnum != 0)
-       {
-               fstrcpy(share, cli->share);
-               fstrcpy(dev  , cli->dev);
-               do_tcon = True;
-       }
-
-       memcpy(&called , &(cli->called ), sizeof(called ));
-       memcpy(&calling, &(cli->calling), sizeof(calling));
-       fstrcpy(dest_host, cli->full_dest_host_name);
-
-       DEBUG(5,("cli_reestablish_connection: %s connecting to %s (ip %s) - %s [%s]\n",
-                nmb_namestr(&calling), nmb_namestr(&called), 
-                inet_ntoa(cli->dest_ip),
-                cli->user_name, cli->domain));
-
-       cli->fd = -1;
-
-       if (cli_establish_connection(cli,
-                                    dest_host, &cli->dest_ip,
-                                    &calling, &called,
-                                    share, dev, False, do_tcon)) {
-               if ((cli->fd != oldfd) && (oldfd != -1)) {
-                       close( oldfd );
-               }
-               return True;
-       }
-       return False;
-}
-
-/****************************************************************************
-establishes a connection right up to doing tconX, reading in a password.
+establishes a connection right up to doing tconX, password in cache.
 ****************************************************************************/
 BOOL cli_establish_connection(struct cli_state *cli, 
                                char *dest_host, struct in_addr *dest_ip,
@@ -1201,7 +1161,7 @@ BOOL cli_establish_connection(struct cli_state *cli,
                        {
                                DEBUG(1,("failed tcon_X\n"));
                                if (do_shutdown)
-                  cli_shutdown(cli);
+                                       cli_shutdown(cli);
                                return False;
                        }
                }
@@ -1213,6 +1173,124 @@ BOOL cli_establish_connection(struct cli_state *cli,
        return True;
 }
 
+/* Initialise client credentials for authenticated pipe access */
+
+static void init_creds(struct ntuser_creds *creds, char* username,
+                      char* domain, char* password, int pass_len)
+{
+       ZERO_STRUCTP(creds);
+
+       pwd_set_cleartext(&creds->pwd, password);
+
+       fstrcpy(creds->user_name, username);
+       fstrcpy(creds->domain, domain);
+
+       if (!*username) {
+               creds->pwd.null_pwd = True;
+       }
+}
+
+/****************************************************************************
+establishes a connection right up to doing tconX, password specified.
+****************************************************************************/
+NTSTATUS cli_full_connection(struct cli_state **output_cli, 
+                            const char *my_name, const char *dest_host, 
+                            struct in_addr *dest_ip, int port,
+                            char *service, char *service_type,
+                            char *user, char *domain, 
+                            char *password, int pass_len) 
+{
+       struct ntuser_creds creds;
+       NTSTATUS nt_status;
+       struct nmb_name calling;
+       struct nmb_name called;
+       struct cli_state *cli;
+       struct in_addr ip;
+       
+       if (!output_cli) {
+               DEBUG(0, ("output_cli is NULL!?!"));
+       }
+
+       *output_cli = NULL;
+       
+       make_nmb_name(&calling, my_name, 0x0);
+       make_nmb_name(&called , dest_host, 0x20);
+
+again:
+
+       if (!(cli = cli_initialise(NULL))) {
+               return NT_STATUS_NO_MEMORY;
+       }
+       
+       if (cli_set_port(cli, port) != port) {
+               return NT_STATUS_UNSUCCESSFUL;
+       }
+
+       ip = *dest_ip;
+       
+       DEBUG(3,("Connecting to host=%s share=%s\n\n", 
+                dest_host, service));
+       
+       if (!cli_connect(cli, dest_host, &ip))
+       {
+               DEBUG(1,("cli_establish_connection: failed to connect to %s (%s)\n",
+                        nmb_namestr(&called), inet_ntoa(*dest_ip)));
+               return NT_STATUS_UNSUCCESSFUL;
+       }
+
+       if (!cli_session_request(cli, &calling, &called)) {
+               char *p;
+               DEBUG(1,("session request to %s failed (%s)\n", 
+                        called.name, cli_errstr(cli)));
+               cli_shutdown(cli);
+               if ((p=strchr(called.name, '.'))) {
+                       *p = 0;
+                       goto again;
+               }
+               if (strcmp(called.name, "*SMBSERVER")) {
+                       make_nmb_name(&called , "*SMBSERVER", 0x20);
+                       goto again;
+               }
+               return NT_STATUS_UNSUCCESSFUL;
+       }
+
+       if (!cli_negprot(cli))
+       {
+               DEBUG(1,("failed negprot\n"));
+               nt_status = NT_STATUS_UNSUCCESSFUL;
+               cli_shutdown(cli);
+               return nt_status;
+       }
+
+       if (!cli_session_setup(cli, user,
+                              password, pass_len,
+                              NULL, 0,
+                              domain))
+       {
+               DEBUG(1,("failed session setup\n"));
+               nt_status = cli_nt_error(cli);
+               cli_shutdown(cli);
+               return nt_status;
+       } 
+
+       if (service)
+       {
+               if (!cli_send_tconX(cli, service, service_type,
+                                   (char*)password, pass_len))
+               {
+                       DEBUG(1,("failed tcon_X\n"));
+                       nt_status = cli_nt_error(cli);
+                       cli_shutdown(cli);
+                       return nt_status;
+               }
+       }
+
+       init_creds(&creds, user, domain, password, pass_len);
+       cli_init_creds(cli, &creds);
+
+       *output_cli = cli;
+       return NT_STATUS_OK;
+}
 
 /****************************************************************************
  Attempt a NetBIOS session request, falling back to *SMBSERVER if needed.
@@ -1253,9 +1331,9 @@ BOOL attempt_netbios_session_request(struct cli_state *cli, char *srchost, char
 
         DEBUG(0,("attempt_netbios_session_request: %s rejected the session for name *SMBSERVER \
 with error %s.\n", desthost, cli_errstr(cli) ));
-           cli_shutdown(cli);
-               return False;
-       }
+       cli_shutdown(cli);
+       return False;
+    }
 
     cli_shutdown(cli);
 
@@ -1271,3 +1349,5 @@ name *SMBSERVER with error %s\n", desthost, cli_errstr(cli) ));
 
   return True;
 }
+
+